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 <dev/isci/scil/scif_controller.h>
37230557Sjimharris#include <dev/isci/scil/scif_user_callback.h>
38230557Sjimharris
39230557Sjimharris/**
40230557Sjimharris * @brief This user callback will inform the user that a task management
41230557Sjimharris *        request completed.
42230557Sjimharris *
43230557Sjimharris * @param[in]  controller This parameter specifies the controller on
44230557Sjimharris *             which the task management request is completing.
45230557Sjimharris * @param[in]  remote_device This parameter specifies the remote device on
46230557Sjimharris *             which this task management request is completing.
47230557Sjimharris * @param[in]  task_request This parameter specifies the task management
48230557Sjimharris *             request that has completed.
49230557Sjimharris * @param[in]  completion_status This parameter specifies the results of
50230557Sjimharris *             the IO request operation.  SCI_TASK_SUCCESS indicates
51230557Sjimharris *             successful completion.
52230557Sjimharris *
53230557Sjimharris * @return none
54230557Sjimharris */
55230557Sjimharrisvoid
56230557Sjimharrisscif_cb_task_request_complete(SCI_CONTROLLER_HANDLE_T controller,
57230557Sjimharris    SCI_REMOTE_DEVICE_HANDLE_T remote_device,
58230557Sjimharris    SCI_TASK_REQUEST_HANDLE_T task_request, SCI_TASK_STATUS completion_status)
59230557Sjimharris{
60230557Sjimharris
61230557Sjimharris	scif_controller_complete_task(controller, remote_device, task_request);
62230557Sjimharris	isci_task_request_complete(controller, remote_device, task_request,
63230557Sjimharris	    completion_status);
64230557Sjimharris}
65230557Sjimharris
66230557Sjimharris/**
67230557Sjimharris * @brief This method returns the Logical Unit to be utilized for this
68230557Sjimharris *        task management request.
69230557Sjimharris *
70230557Sjimharris * @note The contents of the value returned from this callback are defined
71230557Sjimharris *       by the protocol standard (e.g. T10 SAS specification).  Please
72230557Sjimharris *       refer to the transport task information unit description
73230557Sjimharris *       in the associated standard.
74230557Sjimharris *
75230557Sjimharris * @param[in] scif_user_task_request This parameter points to the user's
76230557Sjimharris *            task request object.  It is a cookie that allows the user to
77230557Sjimharris *            provide the necessary information for this callback.
78230557Sjimharris *
79230557Sjimharris * @return This method returns the LUN associated with this request.
80230557Sjimharris * @todo This should be U64?
81230557Sjimharris */
82230557Sjimharrisuint32_t
83230557Sjimharrisscif_cb_task_request_get_lun(void * scif_user_task_request)
84230557Sjimharris{
85230557Sjimharris
86230557Sjimharris	/* Currently we are only doing hard resets, not LUN resets.  So
87230557Sjimharris	 *  always returning 0 is OK here, since LUN doesn't matter for
88230557Sjimharris	 *  a hard device reset.
89230557Sjimharris	 */
90230557Sjimharris	return (0);
91230557Sjimharris}
92230557Sjimharris
93230557Sjimharris/**
94230557Sjimharris * @brief This method returns the task management function to be utilized
95230557Sjimharris *        for this task request.
96230557Sjimharris *
97230557Sjimharris * @note The contents of the value returned from this callback are defined
98230557Sjimharris *       by the protocol standard (e.g. T10 SAS specification).  Please
99230557Sjimharris *       refer to the transport task information unit description
100230557Sjimharris *       in the associated standard.
101230557Sjimharris *
102230557Sjimharris * @param[in] scif_user_task_request This parameter points to the user's
103230557Sjimharris *            task request object.  It is a cookie that allows the user to
104230557Sjimharris *            provide the necessary information for this callback.
105230557Sjimharris *
106230557Sjimharris * @return This method returns an unsigned byte representing the task
107230557Sjimharris *         management function to be performed.
108230557Sjimharris */
109230557Sjimharrisuint8_t scif_cb_task_request_get_function(void * scif_user_task_request)
110230557Sjimharris{
111230557Sjimharris	/* SCIL supports many types of task management functions, but this
112230557Sjimharris	 *  driver only uses HARD_RESET.
113230557Sjimharris	 */
114230557Sjimharris	return (SCI_SAS_HARD_RESET);
115230557Sjimharris}
116230557Sjimharris
117230557Sjimharris/**
118230557Sjimharris * @brief This method returns the task management IO tag to be managed.
119230557Sjimharris *        Depending upon the task management function the value returned
120230557Sjimharris *        from this method may be ignored.
121230557Sjimharris *
122230557Sjimharris * @param[in] scif_user_task_request This parameter points to the user's
123230557Sjimharris *            task request object.  It is a cookie that allows the user to
124230557Sjimharris *            provide the necessary information for this callback.
125230557Sjimharris *
126230557Sjimharris * @return This method returns an unsigned 16-bit word depicting the IO
127230557Sjimharris *         tag to be managed.
128230557Sjimharris */
129230557Sjimharrisuint16_t
130230557Sjimharrisscif_cb_task_request_get_io_tag_to_manage(void * scif_user_task_request)
131230557Sjimharris{
132230557Sjimharris
133230557Sjimharris	return (0);
134230557Sjimharris}
135230557Sjimharris
136230557Sjimharris/**
137230557Sjimharris * @brief This callback method asks the user to provide the virtual
138230557Sjimharris *        address of the response data buffer for the supplied IO request.
139230557Sjimharris *
140230557Sjimharris * @param[in] scif_user_task_request This parameter points to the user's
141230557Sjimharris *            task request object.  It is a cookie that allows the user to
142230557Sjimharris *            provide the necessary information for this callback.
143230557Sjimharris *
144230557Sjimharris * @return This method returns the virtual address for the response data buffer
145230557Sjimharris *         associated with this IO request.
146230557Sjimharris */
147230557Sjimharrisvoid *
148230557Sjimharrisscif_cb_task_request_get_response_data_address(void * scif_user_task_request)
149230557Sjimharris{
150230557Sjimharris	struct ISCI_TASK_REQUEST *task_request =
151230557Sjimharris	    (struct ISCI_TASK_REQUEST *)scif_user_task_request;
152230557Sjimharris
153230557Sjimharris	return (&task_request->sense_data);
154230557Sjimharris}
155230557Sjimharris
156230557Sjimharris/**
157230557Sjimharris * @brief This callback method asks the user to provide the length of the
158230557Sjimharris *        response data buffer for the supplied IO request.
159230557Sjimharris *
160230557Sjimharris * @param[in] scif_user_task_request This parameter points to the user's
161230557Sjimharris *            task request object.  It is a cookie that allows the user to
162230557Sjimharris *            provide the necessary information for this callback.
163230557Sjimharris *
164230557Sjimharris * @return This method returns the length of the response buffer data
165230557Sjimharris *         associated with this IO request.
166230557Sjimharris */
167230557Sjimharrisuint32_t
168230557Sjimharrisscif_cb_task_request_get_response_data_length(void * scif_user_task_request)
169230557Sjimharris{
170230557Sjimharris
171230557Sjimharris	return (sizeof(struct scsi_sense_data));
172230557Sjimharris}
173230557Sjimharris
174230557Sjimharrisvoid
175230557Sjimharrisisci_task_request_complete(SCI_CONTROLLER_HANDLE_T scif_controller,
176230557Sjimharris    SCI_REMOTE_DEVICE_HANDLE_T remote_device,
177230557Sjimharris    SCI_TASK_REQUEST_HANDLE_T task_request, SCI_TASK_STATUS completion_status)
178230557Sjimharris{
179230557Sjimharris	struct ISCI_TASK_REQUEST *isci_task_request =
180230557Sjimharris		(struct ISCI_TASK_REQUEST *)sci_object_get_association(task_request);
181230557Sjimharris	struct ISCI_CONTROLLER *isci_controller =
182230557Sjimharris		(struct ISCI_CONTROLLER *)sci_object_get_association(scif_controller);
183230557Sjimharris	struct ISCI_REMOTE_DEVICE *isci_remote_device =
184230557Sjimharris		(struct ISCI_REMOTE_DEVICE *)sci_object_get_association(remote_device);
185230557Sjimharris	struct ISCI_REMOTE_DEVICE *pending_remote_device;
186230557Sjimharris	BOOL retry_task = FALSE;
187230557Sjimharris	union ccb *ccb = isci_task_request->ccb;
188230557Sjimharris
189230557Sjimharris	isci_remote_device->is_resetting = FALSE;
190230557Sjimharris
191233710Sdim	switch ((int)completion_status) {
192230557Sjimharris	case SCI_TASK_SUCCESS:
193230557Sjimharris	case SCI_TASK_FAILURE_RESPONSE_VALID:
194230557Sjimharris		break;
195230557Sjimharris
196230557Sjimharris	case SCI_TASK_FAILURE_INVALID_STATE:
197256231Sjimharris		retry_task = TRUE;
198256231Sjimharris		isci_log_message(0, "ISCI",
199256231Sjimharris		    "task failure (invalid state) - retrying\n");
200256231Sjimharris		break;
201256231Sjimharris
202230557Sjimharris	case SCI_TASK_FAILURE_INSUFFICIENT_RESOURCES:
203230557Sjimharris		retry_task = TRUE;
204230557Sjimharris		isci_log_message(0, "ISCI",
205256231Sjimharris		    "task failure (insufficient resources) - retrying\n");
206230557Sjimharris		break;
207230557Sjimharris
208256231Sjimharris	case SCI_FAILURE_TIMEOUT:
209256231Sjimharris		retry_task = TRUE;
210256231Sjimharris		isci_log_message(0, "ISCI", "task timeout - retrying\n");
211256231Sjimharris		break;
212256231Sjimharris
213230557Sjimharris	case SCI_TASK_FAILURE:
214230557Sjimharris	case SCI_TASK_FAILURE_UNSUPPORTED_PROTOCOL:
215230557Sjimharris	case SCI_TASK_FAILURE_INVALID_TAG:
216230557Sjimharris	case SCI_TASK_FAILURE_CONTROLLER_SPECIFIC_ERR:
217230557Sjimharris	case SCI_TASK_FAILURE_TERMINATED:
218230557Sjimharris	case SCI_TASK_FAILURE_INVALID_PARAMETER_VALUE:
219230557Sjimharris		isci_log_message(0, "ISCI",
220230557Sjimharris		    "unhandled task completion code 0x%x\n", completion_status);
221230557Sjimharris		break;
222230557Sjimharris
223230557Sjimharris	default:
224230557Sjimharris		isci_log_message(0, "ISCI",
225230557Sjimharris		    "unhandled task completion code 0x%x\n", completion_status);
226230557Sjimharris		break;
227230557Sjimharris	}
228230557Sjimharris
229230557Sjimharris	if (isci_controller->is_frozen == TRUE) {
230230557Sjimharris		isci_controller->is_frozen = FALSE;
231230557Sjimharris		xpt_release_simq(isci_controller->sim, TRUE);
232230557Sjimharris	}
233230557Sjimharris
234230557Sjimharris	sci_pool_put(isci_controller->request_pool,
235230557Sjimharris	    (struct ISCI_REQUEST *)isci_task_request);
236230557Sjimharris
237230557Sjimharris	/* Make sure we release the device queue, since it may have been frozen
238230557Sjimharris	 *  if someone tried to start an I/O while the task was in progress.
239230557Sjimharris	 */
240230557Sjimharris	isci_remote_device_release_device_queue(isci_remote_device);
241230557Sjimharris
242230557Sjimharris	if (retry_task == TRUE)
243230557Sjimharris		isci_remote_device_reset(isci_remote_device, ccb);
244230557Sjimharris	else {
245230557Sjimharris		pending_remote_device = sci_fast_list_remove_head(
246230557Sjimharris		    &isci_controller->pending_device_reset_list);
247230557Sjimharris
248230557Sjimharris		if (pending_remote_device != NULL) {
249230557Sjimharris			/* Any resets that were triggered from an XPT_RESET_DEV
250230557Sjimharris			 *  CCB are never put in the pending list if the request
251230557Sjimharris			 *  pool is empty - they are given back to CAM to be
252230557Sjimharris			 *  requeued.  So we will alawys pass NULL here,
253230557Sjimharris			 *  denoting that there is no CCB associated with the
254230557Sjimharris			 *  device reset.
255230557Sjimharris			 */
256230557Sjimharris			isci_remote_device_reset(pending_remote_device, NULL);
257230557Sjimharris		} else if (ccb != NULL) {
258230557Sjimharris			/* There was a CCB associated with this reset, so mark
259230557Sjimharris			 *  it complete and return it to CAM.
260230557Sjimharris			 */
261230557Sjimharris			ccb->ccb_h.status &= ~CAM_STATUS_MASK;
262230557Sjimharris			ccb->ccb_h.status |= CAM_REQ_CMP;
263230557Sjimharris			xpt_done(ccb);
264230557Sjimharris		}
265230557Sjimharris	}
266230557Sjimharris}
267230557Sjimharris
268