1144966Svkashyap/*
2169400Sscottl * Copyright (c) 2004-07 Applied Micro Circuits Corporation.
3144966Svkashyap * Copyright (c) 2004-05 Vinod Kashyap
4144966Svkashyap * All rights reserved.
5144966Svkashyap *
6144966Svkashyap * Redistribution and use in source and binary forms, with or without
7144966Svkashyap * modification, are permitted provided that the following conditions
8144966Svkashyap * are met:
9144966Svkashyap * 1. Redistributions of source code must retain the above copyright
10144966Svkashyap *    notice, this list of conditions and the following disclaimer.
11144966Svkashyap * 2. Redistributions in binary form must reproduce the above copyright
12144966Svkashyap *    notice, this list of conditions and the following disclaimer in the
13144966Svkashyap *    documentation and/or other materials provided with the distribution.
14144966Svkashyap *
15144966Svkashyap * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16144966Svkashyap * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17144966Svkashyap * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18144966Svkashyap * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19144966Svkashyap * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20144966Svkashyap * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21144966Svkashyap * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22144966Svkashyap * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23144966Svkashyap * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24144966Svkashyap * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25144966Svkashyap * SUCH DAMAGE.
26144966Svkashyap *
27144966Svkashyap *	$FreeBSD: releng/10.3/sys/dev/twa/tw_cl_intr.c 212008 2010-08-30 19:15:04Z delphij $
28144966Svkashyap */
29144966Svkashyap
30144966Svkashyap/*
31144966Svkashyap * AMCC'S 3ware driver for 9000 series storage controllers.
32144966Svkashyap *
33144966Svkashyap * Author: Vinod Kashyap
34169400Sscottl * Modifications by: Adam Radford
35172496Sscottl * Modifications by: Manjunath Ranganathaiah
36144966Svkashyap */
37144966Svkashyap
38144966Svkashyap
39144966Svkashyap/*
40144966Svkashyap * Common Layer interrupt handling functions.
41144966Svkashyap */
42144966Svkashyap
43144966Svkashyap
44144966Svkashyap#include "tw_osl_share.h"
45144966Svkashyap#include "tw_cl_share.h"
46144966Svkashyap#include "tw_cl_fwif.h"
47144966Svkashyap#include "tw_cl_ioctl.h"
48144966Svkashyap#include "tw_cl.h"
49144966Svkashyap#include "tw_cl_externs.h"
50144966Svkashyap#include "tw_osl_ioctl.h"
51144966Svkashyap
52144966Svkashyap
53144966Svkashyap
54144966Svkashyap/*
55144966Svkashyap * Function name:	twa_interrupt
56144966Svkashyap * Description:		Interrupt handler.  Determines the kind of interrupt,
57144966Svkashyap *			and returns TW_CL_TRUE if it recognizes the interrupt.
58144966Svkashyap *
59144966Svkashyap * Input:		ctlr_handle	-- controller handle
60144966Svkashyap * Output:		None
61144966Svkashyap * Return value:	TW_CL_TRUE -- interrupt recognized
62144966Svkashyap *			TW_CL_FALSE-- interrupt not recognized
63144966Svkashyap */
64144966SvkashyapTW_INT32
65144966Svkashyaptw_cl_interrupt(struct tw_cl_ctlr_handle *ctlr_handle)
66144966Svkashyap{
67144966Svkashyap	struct tw_cli_ctlr_context	*ctlr =
68144966Svkashyap		(struct tw_cli_ctlr_context *)(ctlr_handle->cl_ctlr_ctxt);
69144966Svkashyap	TW_UINT32			status_reg;
70144966Svkashyap	TW_INT32			rc = TW_CL_FALSE;
71144966Svkashyap
72144966Svkashyap	tw_cli_dbg_printf(10, ctlr_handle, tw_osl_cur_func(), "entered");
73144966Svkashyap
74169400Sscottl	/* If we don't have controller context, bail */
75169400Sscottl	if (ctlr == NULL)
76169400Sscottl		goto out;
77169400Sscottl
78144966Svkashyap	/*
79208969Sdelphij	 * Bail If we get an interrupt while resetting, or shutting down.
80144966Svkashyap	 */
81208969Sdelphij	if (ctlr->reset_in_progress || !(ctlr->active))
82208969Sdelphij		goto out;
83144966Svkashyap
84144966Svkashyap	/* Read the status register to determine the type of interrupt. */
85144966Svkashyap	status_reg = TW_CLI_READ_STATUS_REGISTER(ctlr_handle);
86144966Svkashyap	if (tw_cli_check_ctlr_state(ctlr, status_reg))
87208969Sdelphij		goto out;
88144966Svkashyap
89144966Svkashyap	/* Clear the interrupt. */
90144966Svkashyap	if (status_reg & TWA_STATUS_HOST_INTERRUPT) {
91144966Svkashyap		tw_cli_dbg_printf(6, ctlr_handle, tw_osl_cur_func(),
92144966Svkashyap			"Host interrupt");
93144966Svkashyap		TW_CLI_WRITE_CONTROL_REGISTER(ctlr_handle,
94144966Svkashyap			TWA_CONTROL_CLEAR_HOST_INTERRUPT);
95144966Svkashyap	}
96144966Svkashyap	if (status_reg & TWA_STATUS_ATTENTION_INTERRUPT) {
97144966Svkashyap		tw_cli_dbg_printf(6, ctlr_handle, tw_osl_cur_func(),
98144966Svkashyap			"Attention interrupt");
99208969Sdelphij		rc |= TW_CL_TRUE; /* request for a deferred isr call */
100208969Sdelphij		tw_cli_process_attn_intr(ctlr);
101144966Svkashyap		TW_CLI_WRITE_CONTROL_REGISTER(ctlr_handle,
102144966Svkashyap			TWA_CONTROL_CLEAR_ATTENTION_INTERRUPT);
103144966Svkashyap	}
104144966Svkashyap	if (status_reg & TWA_STATUS_COMMAND_INTERRUPT) {
105144966Svkashyap		tw_cli_dbg_printf(6, ctlr_handle, tw_osl_cur_func(),
106144966Svkashyap			"Command interrupt");
107144966Svkashyap		rc |= TW_CL_TRUE; /* request for a deferred isr call */
108208969Sdelphij		tw_cli_process_cmd_intr(ctlr);
109208969Sdelphij		if ((TW_CL_Q_FIRST_ITEM(&(ctlr->req_q_head[TW_CLI_PENDING_Q]))) == TW_CL_NULL)
110208969Sdelphij			TW_CLI_WRITE_CONTROL_REGISTER(ctlr_handle,
111208969Sdelphij				TWA_CONTROL_MASK_COMMAND_INTERRUPT);
112144966Svkashyap	}
113144966Svkashyap	if (status_reg & TWA_STATUS_RESPONSE_INTERRUPT) {
114144966Svkashyap		tw_cli_dbg_printf(10, ctlr_handle, tw_osl_cur_func(),
115144966Svkashyap			"Response interrupt");
116144966Svkashyap		rc |= TW_CL_TRUE; /* request for a deferred isr call */
117208969Sdelphij		tw_cli_process_resp_intr(ctlr);
118144966Svkashyap	}
119169400Sscottlout:
120144966Svkashyap	return(rc);
121144966Svkashyap}
122144966Svkashyap
123144966Svkashyap
124144966Svkashyap
125144966Svkashyap/*
126144966Svkashyap * Function name:	tw_cli_process_host_intr
127144966Svkashyap * Description:		This function gets called if we triggered an interrupt.
128144966Svkashyap *			We don't use it as of now.
129144966Svkashyap *
130144966Svkashyap * Input:		ctlr	-- ptr to CL internal ctlr context
131144966Svkashyap * Output:		None
132144966Svkashyap * Return value:	None
133144966Svkashyap */
134144966SvkashyapTW_VOID
135144966Svkashyaptw_cli_process_host_intr(struct tw_cli_ctlr_context *ctlr)
136144966Svkashyap{
137144966Svkashyap	tw_cli_dbg_printf(6, ctlr->ctlr_handle, tw_osl_cur_func(), "entered");
138144966Svkashyap}
139144966Svkashyap
140144966Svkashyap
141144966Svkashyap
142144966Svkashyap/*
143144966Svkashyap * Function name:	tw_cli_process_attn_intr
144144966Svkashyap * Description:		This function gets called if the fw posted an AEN
145144966Svkashyap *			(Asynchronous Event Notification).  It fetches
146144966Svkashyap *			all the AEN's that the fw might have posted.
147144966Svkashyap *
148144966Svkashyap * Input:		ctlr	-- ptr to CL internal ctlr context
149144966Svkashyap * Output:		None
150144966Svkashyap * Return value:	None
151144966Svkashyap */
152144966SvkashyapTW_VOID
153144966Svkashyaptw_cli_process_attn_intr(struct tw_cli_ctlr_context *ctlr)
154144966Svkashyap{
155144966Svkashyap	TW_INT32	error;
156144966Svkashyap
157144966Svkashyap	tw_cli_dbg_printf(6, ctlr->ctlr_handle, tw_osl_cur_func(), "entered");
158144966Svkashyap
159144966Svkashyap	if ((error = tw_cli_get_aen(ctlr))) {
160144966Svkashyap		/*
161144966Svkashyap		 * If the driver is already in the process of retrieveing AEN's,
162144966Svkashyap		 * we will be returned TW_OSL_EBUSY.  In this case,
163144966Svkashyap		 * tw_cli_param_callback or tw_cli_aen_callback will eventually
164144966Svkashyap		 * retrieve the AEN this attention interrupt is for.  So, we
165144966Svkashyap		 * don't need to print the failure.
166144966Svkashyap		 */
167144966Svkashyap		if (error != TW_OSL_EBUSY)
168144966Svkashyap			tw_cl_create_event(ctlr->ctlr_handle, TW_CL_FALSE,
169144966Svkashyap				TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR,
170144966Svkashyap				0x1200, 0x1, TW_CL_SEVERITY_ERROR_STRING,
171144966Svkashyap				"Failed to fetch AEN",
172144966Svkashyap				"error = %d", error);
173144966Svkashyap	}
174144966Svkashyap}
175144966Svkashyap
176144966Svkashyap
177144966Svkashyap
178144966Svkashyap/*
179144966Svkashyap * Function name:	tw_cli_process_cmd_intr
180144966Svkashyap * Description:		This function gets called if we hit a queue full
181144966Svkashyap *			condition earlier, and the fw is now ready for
182144966Svkashyap *			new cmds.  Submits any pending requests.
183144966Svkashyap *
184144966Svkashyap * Input:		ctlr	-- ptr to CL internal ctlr context
185144966Svkashyap * Output:		None
186144966Svkashyap * Return value:	None
187144966Svkashyap */
188144966SvkashyapTW_VOID
189144966Svkashyaptw_cli_process_cmd_intr(struct tw_cli_ctlr_context *ctlr)
190144966Svkashyap{
191144966Svkashyap	tw_cli_dbg_printf(6, ctlr->ctlr_handle, tw_osl_cur_func(), "entered");
192144966Svkashyap
193144966Svkashyap	/* Start any requests that might be in the pending queue. */
194144966Svkashyap	tw_cli_submit_pending_queue(ctlr);
195144966Svkashyap
196144966Svkashyap	/*
197144966Svkashyap	 * If tw_cli_submit_pending_queue was unsuccessful due to a "cmd queue
198144966Svkashyap	 * full" condition, cmd_intr will already have been unmasked by
199144966Svkashyap	 * tw_cli_submit_cmd.  We don't need to do it again... simply return.
200144966Svkashyap	 */
201144966Svkashyap}
202144966Svkashyap
203144966Svkashyap
204144966Svkashyap
205144966Svkashyap/*
206144966Svkashyap * Function name:	tw_cli_process_resp_intr
207144966Svkashyap * Description:		Looks for cmd completions from fw; queues cmds completed
208144966Svkashyap *			by fw into complete queue.
209144966Svkashyap *
210144966Svkashyap * Input:		ctlr	-- ptr to CL internal ctlr context
211144966Svkashyap * Output:		None
212144966Svkashyap * Return value:	0	-- no ctlr error
213144966Svkashyap *			non-zero-- ctlr error
214144966Svkashyap */
215144966SvkashyapTW_INT32
216144966Svkashyaptw_cli_process_resp_intr(struct tw_cli_ctlr_context *ctlr)
217144966Svkashyap{
218144966Svkashyap	TW_UINT32			resp;
219144966Svkashyap	struct tw_cli_req_context	*req;
220144966Svkashyap	TW_INT32			error;
221144966Svkashyap	TW_UINT32			status_reg;
222144966Svkashyap
223144966Svkashyap	tw_cli_dbg_printf(10, ctlr->ctlr_handle, tw_osl_cur_func(), "entered");
224144966Svkashyap
225144966Svkashyap	for (;;) {
226144966Svkashyap		status_reg = TW_CLI_READ_STATUS_REGISTER(ctlr->ctlr_handle);
227144966Svkashyap		if ((error = tw_cli_check_ctlr_state(ctlr, status_reg)))
228144966Svkashyap			break;
229144966Svkashyap		if (status_reg & TWA_STATUS_RESPONSE_QUEUE_EMPTY) {
230144966Svkashyap			tw_cli_dbg_printf(7, ctlr->ctlr_handle,
231144966Svkashyap				tw_osl_cur_func(), "Response queue empty");
232144966Svkashyap			break;
233144966Svkashyap		}
234144966Svkashyap
235144966Svkashyap		/* Response queue is not empty. */
236144966Svkashyap		resp = TW_CLI_READ_RESPONSE_QUEUE(ctlr->ctlr_handle);
237144966Svkashyap		{
238144966Svkashyap			req = &(ctlr->req_ctxt_buf[GET_RESP_ID(resp)]);
239144966Svkashyap		}
240144966Svkashyap
241144966Svkashyap		if (req->state != TW_CLI_REQ_STATE_BUSY) {
242144966Svkashyap			tw_cl_create_event(ctlr->ctlr_handle, TW_CL_FALSE,
243144966Svkashyap				TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR,
244144966Svkashyap				0x1201, 0x1, TW_CL_SEVERITY_ERROR_STRING,
245144966Svkashyap				"Unposted command completed!!",
246144966Svkashyap				"request = %p, status = %d",
247144966Svkashyap				req, req->state);
248144966Svkashyap#ifdef TW_OSL_DEBUG
249144966Svkashyap			tw_cl_print_ctlr_stats(ctlr->ctlr_handle);
250144966Svkashyap#endif /* TW_OSL_DEBUG */
251212008Sdelphij			continue;
252144966Svkashyap		}
253144966Svkashyap
254144966Svkashyap		/*
255144966Svkashyap		 * Remove the request from the busy queue, mark it as complete,
256144966Svkashyap		 * and enqueue it in the complete queue.
257144966Svkashyap		 */
258144966Svkashyap		tw_cli_req_q_remove_item(req, TW_CLI_BUSY_Q);
259144966Svkashyap		req->state = TW_CLI_REQ_STATE_COMPLETE;
260144966Svkashyap		tw_cli_req_q_insert_tail(req, TW_CLI_COMPLETE_Q);
261152213Svkashyap
262144966Svkashyap	}
263144966Svkashyap
264144966Svkashyap	/* Complete this, and other requests in the complete queue. */
265144966Svkashyap	tw_cli_process_complete_queue(ctlr);
266144966Svkashyap
267144966Svkashyap	return(error);
268144966Svkashyap}
269144966Svkashyap
270144966Svkashyap
271144966Svkashyap
272144966Svkashyap/*
273144966Svkashyap * Function name:	tw_cli_submit_pending_queue
274144966Svkashyap * Description:		Kick starts any requests in the pending queue.
275144966Svkashyap *
276144966Svkashyap * Input:		ctlr	-- ptr to CL internal ctlr context
277144966Svkashyap * Output:		None
278144966Svkashyap * Return value:	0	-- all pending requests submitted successfully
279144966Svkashyap *			non-zero-- otherwise
280144966Svkashyap */
281144966SvkashyapTW_INT32
282144966Svkashyaptw_cli_submit_pending_queue(struct tw_cli_ctlr_context *ctlr)
283144966Svkashyap{
284144966Svkashyap	struct tw_cli_req_context	*req;
285144966Svkashyap	TW_INT32			error = TW_OSL_ESUCCESS;
286144966Svkashyap
287144966Svkashyap	tw_cli_dbg_printf(3, ctlr->ctlr_handle, tw_osl_cur_func(), "entered");
288144966Svkashyap
289144966Svkashyap	/*
290144966Svkashyap	 * Pull requests off the pending queue, and submit them.
291144966Svkashyap	 */
292144966Svkashyap	while ((req = tw_cli_req_q_remove_head(ctlr, TW_CLI_PENDING_Q)) !=
293144966Svkashyap		TW_CL_NULL) {
294144966Svkashyap		if ((error = tw_cli_submit_cmd(req))) {
295144966Svkashyap			if (error == TW_OSL_EBUSY) {
296144966Svkashyap				tw_cli_dbg_printf(2, ctlr->ctlr_handle,
297144966Svkashyap					tw_osl_cur_func(),
298144966Svkashyap					"Requeueing pending request");
299144966Svkashyap				req->state = TW_CLI_REQ_STATE_PENDING;
300144966Svkashyap				/*
301144966Svkashyap				 * Queue the request at the head of the pending
302144966Svkashyap				 * queue, and break away, so we don't try to
303144966Svkashyap				 * submit any more requests.
304144966Svkashyap				 */
305144966Svkashyap				tw_cli_req_q_insert_head(req, TW_CLI_PENDING_Q);
306144966Svkashyap				break;
307144966Svkashyap			} else {
308144966Svkashyap				tw_cl_create_event(ctlr->ctlr_handle,
309144966Svkashyap					TW_CL_FALSE,
310144966Svkashyap					TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR,
311144966Svkashyap					0x1202, 0x1,
312144966Svkashyap					TW_CL_SEVERITY_ERROR_STRING,
313144966Svkashyap					"Could not start request "
314144966Svkashyap					"in pending queue",
315144966Svkashyap					"request = %p, opcode = 0x%x, "
316144966Svkashyap					"error = %d", req,
317144966Svkashyap					GET_OPCODE(req->cmd_pkt->
318144966Svkashyap						command.cmd_pkt_9k.res__opcode),
319144966Svkashyap					error);
320144966Svkashyap				/*
321144966Svkashyap				 * Set the appropriate error and call the CL
322144966Svkashyap				 * internal callback if there's one.  If the
323144966Svkashyap				 * request originator is polling for completion,
324144966Svkashyap				 * he should be checking req->error to
325144966Svkashyap				 * determine that the request did not go
326144966Svkashyap				 * through.  The request originators are
327144966Svkashyap				 * responsible for the clean-up.
328144966Svkashyap				 */
329144966Svkashyap				req->error_code = error;
330144966Svkashyap				req->state = TW_CLI_REQ_STATE_COMPLETE;
331144966Svkashyap				if (req->tw_cli_callback)
332144966Svkashyap					req->tw_cli_callback(req);
333144966Svkashyap				error = TW_OSL_ESUCCESS;
334144966Svkashyap			}
335144966Svkashyap		}
336144966Svkashyap	}
337144966Svkashyap	return(error);
338144966Svkashyap}
339144966Svkashyap
340144966Svkashyap
341144966Svkashyap
342144966Svkashyap/*
343144966Svkashyap * Function name:	tw_cli_process_complete_queue
344144966Svkashyap * Description:		Calls the CL internal callback routine, if any, for
345144966Svkashyap *			each request in the complete queue.
346144966Svkashyap *
347144966Svkashyap * Input:		ctlr	-- ptr to CL internal ctlr context
348144966Svkashyap * Output:		None
349144966Svkashyap * Return value:	None
350144966Svkashyap */
351144966SvkashyapTW_VOID
352144966Svkashyaptw_cli_process_complete_queue(struct tw_cli_ctlr_context *ctlr)
353144966Svkashyap{
354144966Svkashyap	struct tw_cli_req_context	*req;
355144966Svkashyap
356144966Svkashyap	tw_cli_dbg_printf(10, ctlr->ctlr_handle, tw_osl_cur_func(), "entered");
357144966Svkashyap
358144966Svkashyap	/*
359144966Svkashyap	 * Pull commands off the completed list, dispatch them appropriately.
360144966Svkashyap	 */
361144966Svkashyap	while ((req = tw_cli_req_q_remove_head(ctlr, TW_CLI_COMPLETE_Q)) !=
362144966Svkashyap		TW_CL_NULL) {
363144966Svkashyap		/* Call the CL internal callback, if there's one. */
364144966Svkashyap		if (req->tw_cli_callback)
365144966Svkashyap			req->tw_cli_callback(req);
366144966Svkashyap	}
367144966Svkashyap}
368144966Svkashyap
369144966Svkashyap
370144966Svkashyap
371144966Svkashyap/*
372144966Svkashyap * Function name:	tw_cli_complete_io
373144966Svkashyap * Description:		CL internal callback for SCSI/fw passthru requests.
374144966Svkashyap *
375144966Svkashyap * Input:		req	-- ptr to CL internal request context
376144966Svkashyap * Output:		None
377144966Svkashyap * Return value:	None
378144966Svkashyap */
379144966SvkashyapTW_VOID
380144966Svkashyaptw_cli_complete_io(struct tw_cli_req_context *req)
381144966Svkashyap{
382144966Svkashyap	struct tw_cli_ctlr_context	*ctlr = req->ctlr;
383144966Svkashyap	struct tw_cl_req_packet		*req_pkt =
384144966Svkashyap		(struct tw_cl_req_packet *)(req->orig_req);
385144966Svkashyap
386144966Svkashyap	tw_cli_dbg_printf(8, ctlr->ctlr_handle, tw_osl_cur_func(), "entered");
387144966Svkashyap
388144966Svkashyap	req_pkt->status = TW_CL_ERR_REQ_SUCCESS;
389144966Svkashyap	if (req->error_code) {
390144966Svkashyap		req_pkt->status = TW_CL_ERR_REQ_UNABLE_TO_SUBMIT_COMMAND;
391144966Svkashyap		goto out;
392144966Svkashyap	}
393144966Svkashyap
394144966Svkashyap	if (req->state != TW_CLI_REQ_STATE_COMPLETE) {
395144966Svkashyap		tw_cl_create_event(ctlr->ctlr_handle, TW_CL_FALSE,
396144966Svkashyap			TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR,
397144966Svkashyap			0x1203, 0x1, TW_CL_SEVERITY_ERROR_STRING,
398144966Svkashyap			"I/O completion on incomplete command!!",
399144966Svkashyap			"request = %p, status = %d",
400144966Svkashyap			req, req->state);
401144966Svkashyap#ifdef TW_OSL_DEBUG
402144966Svkashyap		tw_cl_print_ctlr_stats(ctlr->ctlr_handle);
403144966Svkashyap#endif /* TW_OSL_DEBUG */
404212008Sdelphij		return;
405144966Svkashyap	}
406144966Svkashyap
407144966Svkashyap	if (req->flags & TW_CLI_REQ_FLAGS_PASSTHRU) {
408144966Svkashyap		/* Copy the command packet back into OSL's space. */
409144966Svkashyap		tw_osl_memcpy(req_pkt->gen_req_pkt.pt_req.cmd_pkt, req->cmd_pkt,
410144966Svkashyap			sizeof(struct tw_cl_command_packet));
411144966Svkashyap	} else
412144966Svkashyap		tw_cli_scsi_complete(req);
413144966Svkashyap
414144966Svkashyapout:
415144966Svkashyap	req_pkt->tw_osl_callback(req->req_handle);
416144966Svkashyap	tw_cli_req_q_insert_tail(req, TW_CLI_FREE_Q);
417144966Svkashyap}
418144966Svkashyap
419144966Svkashyap
420144966Svkashyap
421144966Svkashyap/*
422144966Svkashyap * Function name:	tw_cli_scsi_complete
423144966Svkashyap * Description:		Completion routine for SCSI requests.
424144966Svkashyap *
425144966Svkashyap * Input:		req	-- ptr to CL internal request context
426144966Svkashyap * Output:		None
427144966Svkashyap * Return value:	None
428144966Svkashyap */
429144966SvkashyapTW_VOID
430144966Svkashyaptw_cli_scsi_complete(struct tw_cli_req_context *req)
431144966Svkashyap{
432144966Svkashyap	struct tw_cl_req_packet		*req_pkt =
433144966Svkashyap		(struct tw_cl_req_packet *)(req->orig_req);
434144966Svkashyap	struct tw_cl_scsi_req_packet	*scsi_req =
435144966Svkashyap		&(req_pkt->gen_req_pkt.scsi_req);
436144966Svkashyap	struct tw_cl_command_9k		*cmd =
437144966Svkashyap		&(req->cmd_pkt->command.cmd_pkt_9k);
438144966Svkashyap	struct tw_cl_command_header	*cmd_hdr;
439144966Svkashyap	TW_UINT16			error;
440144966Svkashyap	TW_UINT8			*cdb;
441144966Svkashyap
442144966Svkashyap	tw_cli_dbg_printf(8, req->ctlr->ctlr_handle, tw_osl_cur_func(),
443144966Svkashyap		"entered");
444144966Svkashyap
445144966Svkashyap	scsi_req->scsi_status = cmd->status;
446144966Svkashyap	if (! cmd->status)
447144966Svkashyap		return;
448144966Svkashyap
449144966Svkashyap	tw_cli_dbg_printf(1, req->ctlr->ctlr_handle, tw_osl_cur_func(),
450144966Svkashyap		"req_id = 0x%x, status = 0x%x",
451144966Svkashyap		GET_REQ_ID(cmd->lun_l4__req_id), cmd->status);
452144966Svkashyap
453144966Svkashyap	cmd_hdr = &(req->cmd_pkt->cmd_hdr);
454144966Svkashyap	error = cmd_hdr->status_block.error;
455144966Svkashyap	if ((error == TWA_ERROR_LOGICAL_UNIT_NOT_SUPPORTED) ||
456144966Svkashyap			(error == TWA_ERROR_UNIT_OFFLINE)) {
457144966Svkashyap		if (GET_LUN_L4(cmd->lun_l4__req_id))
458144966Svkashyap			req_pkt->status |= TW_CL_ERR_REQ_INVALID_LUN;
459144966Svkashyap		else
460144966Svkashyap			req_pkt->status |= TW_CL_ERR_REQ_INVALID_TARGET;
461144966Svkashyap	} else {
462144966Svkashyap		tw_cli_dbg_printf(2, req->ctlr->ctlr_handle,
463144966Svkashyap			tw_osl_cur_func(),
464144966Svkashyap			"cmd = %x %x %x %x %x %x %x",
465144966Svkashyap			GET_OPCODE(cmd->res__opcode),
466144966Svkashyap			GET_SGL_OFF(cmd->res__opcode),
467144966Svkashyap			cmd->unit,
468144966Svkashyap			cmd->lun_l4__req_id,
469144966Svkashyap			cmd->status,
470144966Svkashyap			cmd->sgl_offset,
471144966Svkashyap			cmd->lun_h4__sgl_entries);
472144966Svkashyap
473144966Svkashyap		cdb = (TW_UINT8 *)(cmd->cdb);
474144966Svkashyap		tw_cli_dbg_printf(2, req->ctlr->ctlr_handle,
475144966Svkashyap			tw_osl_cur_func(),
476144966Svkashyap			"cdb = %x %x %x %x %x %x %x %x "
477144966Svkashyap			"%x %x %x %x %x %x %x %x",
478144966Svkashyap			cdb[0], cdb[1], cdb[2], cdb[3],
479144966Svkashyap			cdb[4], cdb[5], cdb[6], cdb[7],
480144966Svkashyap			cdb[8], cdb[9], cdb[10], cdb[11],
481144966Svkashyap			cdb[12], cdb[13], cdb[14], cdb[15]);
482144966Svkashyap
483212008Sdelphij#if       0
484144966Svkashyap		/*
485144966Svkashyap		 * Print the error. Firmware doesn't yet support
486144966Svkashyap		 * the 'Mode Sense' cmd.  Don't print if the cmd
487144966Svkashyap		 * is 'Mode Sense', and the error is 'Invalid field
488144966Svkashyap		 * in CDB'.
489144966Svkashyap		 */
490144966Svkashyap		if (! ((cdb[0] == 0x1A) && (error == 0x10D)))
491144966Svkashyap			tw_cli_create_ctlr_event(req->ctlr,
492144966Svkashyap				TW_CL_MESSAGE_SOURCE_CONTROLLER_ERROR,
493144966Svkashyap				cmd_hdr);
494212008Sdelphij#endif // 0
495144966Svkashyap	}
496144966Svkashyap
497144966Svkashyap	if (scsi_req->sense_data) {
498144966Svkashyap		tw_osl_memcpy(scsi_req->sense_data, cmd_hdr->sense_data,
499144966Svkashyap			TWA_SENSE_DATA_LENGTH);
500144966Svkashyap		scsi_req->sense_len = TWA_SENSE_DATA_LENGTH;
501144966Svkashyap		req_pkt->status |= TW_CL_ERR_REQ_AUTO_SENSE_VALID;
502144966Svkashyap	}
503144966Svkashyap	req_pkt->status |= TW_CL_ERR_REQ_SCSI_ERROR;
504144966Svkashyap}
505144966Svkashyap
506144966Svkashyap
507144966Svkashyap
508144966Svkashyap/*
509144966Svkashyap * Function name:	tw_cli_param_callback
510144966Svkashyap * Description:		Callback for get/set_param requests.
511144966Svkashyap *
512144966Svkashyap * Input:		req	-- ptr to completed request pkt
513144966Svkashyap * Output:		None
514144966Svkashyap * Return value:	None
515144966Svkashyap */
516144966SvkashyapTW_VOID
517144966Svkashyaptw_cli_param_callback(struct tw_cli_req_context *req)
518144966Svkashyap{
519144966Svkashyap	struct tw_cli_ctlr_context	*ctlr = req->ctlr;
520144966Svkashyap	union tw_cl_command_7k		*cmd =
521144966Svkashyap		&(req->cmd_pkt->command.cmd_pkt_7k);
522144966Svkashyap	TW_INT32			error;
523144966Svkashyap
524144966Svkashyap	tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(), "entered");
525144966Svkashyap
526144966Svkashyap	/*
527144966Svkashyap	 * If the request was never submitted to the controller, the function
528144966Svkashyap	 * that sets req->error is responsible for calling tw_cl_create_event.
529144966Svkashyap	 */
530144966Svkashyap	if (! req->error_code)
531144966Svkashyap		if (cmd->param.status) {
532212008Sdelphij#if       0
533144966Svkashyap			tw_cli_create_ctlr_event(ctlr,
534144966Svkashyap				TW_CL_MESSAGE_SOURCE_CONTROLLER_ERROR,
535144966Svkashyap				&(req->cmd_pkt->cmd_hdr));
536212008Sdelphij#endif // 0
537144966Svkashyap			tw_cl_create_event(ctlr->ctlr_handle, TW_CL_FALSE,
538144966Svkashyap				TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR,
539144966Svkashyap				0x1204, 0x1, TW_CL_SEVERITY_ERROR_STRING,
540144966Svkashyap				"get/set_param failed",
541144966Svkashyap				"status = %d", cmd->param.status);
542144966Svkashyap		}
543144966Svkashyap
544208969Sdelphij	ctlr->internal_req_busy = TW_CL_FALSE;
545144966Svkashyap	tw_cli_req_q_insert_tail(req, TW_CLI_FREE_Q);
546144966Svkashyap
547208969Sdelphij	if ((ctlr->get_more_aens) && (!(ctlr->reset_in_progress))) {
548208969Sdelphij		ctlr->get_more_aens = TW_CL_FALSE;
549144966Svkashyap		tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(),
550144966Svkashyap			"Fetching more AEN's");
551144966Svkashyap		if ((error = tw_cli_get_aen(ctlr)))
552144966Svkashyap			tw_cl_create_event(ctlr->ctlr_handle, TW_CL_FALSE,
553144966Svkashyap				TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR,
554144966Svkashyap				0x1205, 0x1, TW_CL_SEVERITY_ERROR_STRING,
555144966Svkashyap				"Failed to fetch all AEN's from param_callback",
556144966Svkashyap				"error = %d", error);
557144966Svkashyap	}
558144966Svkashyap}
559144966Svkashyap
560144966Svkashyap
561144966Svkashyap
562144966Svkashyap/*
563144966Svkashyap * Function name:	tw_cli_aen_callback
564144966Svkashyap * Description:		Callback for requests to fetch AEN's.
565144966Svkashyap *
566144966Svkashyap * Input:		req	-- ptr to completed request pkt
567144966Svkashyap * Output:		None
568144966Svkashyap * Return value:	None
569144966Svkashyap */
570144966SvkashyapTW_VOID
571144966Svkashyaptw_cli_aen_callback(struct tw_cli_req_context *req)
572144966Svkashyap{
573144966Svkashyap	struct tw_cli_ctlr_context	*ctlr = req->ctlr;
574144966Svkashyap	struct tw_cl_command_header	*cmd_hdr;
575144966Svkashyap	struct tw_cl_command_9k		*cmd =
576144966Svkashyap		&(req->cmd_pkt->command.cmd_pkt_9k);
577144966Svkashyap	TW_UINT16			aen_code = TWA_AEN_QUEUE_EMPTY;
578144966Svkashyap	TW_INT32			error;
579144966Svkashyap
580144966Svkashyap	tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(), "entered");
581144966Svkashyap
582144966Svkashyap	tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(),
583144966Svkashyap		"req_id = 0x%x, req error = %d, status = 0x%x",
584144966Svkashyap		GET_REQ_ID(cmd->lun_l4__req_id), req->error_code, cmd->status);
585144966Svkashyap
586144966Svkashyap	/*
587144966Svkashyap	 * If the request was never submitted to the controller, the function
588144966Svkashyap	 * that sets error is responsible for calling tw_cl_create_event.
589144966Svkashyap	 */
590144966Svkashyap	if (!(error = req->error_code))
591144966Svkashyap		if ((error = cmd->status)) {
592144966Svkashyap			cmd_hdr = (struct tw_cl_command_header *)
593144966Svkashyap				(&(req->cmd_pkt->cmd_hdr));
594212008Sdelphij#if       0
595144966Svkashyap			tw_cli_create_ctlr_event(ctlr,
596144966Svkashyap				TW_CL_MESSAGE_SOURCE_CONTROLLER_ERROR,
597144966Svkashyap				cmd_hdr);
598212008Sdelphij#endif // 0
599144966Svkashyap			tw_cl_create_event(ctlr->ctlr_handle, TW_CL_FALSE,
600144966Svkashyap				TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR,
601144966Svkashyap				0x1206, 0x1, TW_CL_SEVERITY_ERROR_STRING,
602144966Svkashyap				"Request Sense failed",
603144966Svkashyap				"opcode = 0x%x, status = %d",
604144966Svkashyap				GET_OPCODE(cmd->res__opcode), cmd->status);
605144966Svkashyap		}
606144966Svkashyap
607144966Svkashyap	if (error) {
608208969Sdelphij		ctlr->internal_req_busy = TW_CL_FALSE;
609144966Svkashyap		tw_cli_req_q_insert_tail(req, TW_CLI_FREE_Q);
610144966Svkashyap		return;
611144966Svkashyap	}
612144966Svkashyap
613144966Svkashyap	tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(),
614144966Svkashyap		"Request Sense command succeeded");
615144966Svkashyap
616144966Svkashyap	aen_code = tw_cli_manage_aen(ctlr, req);
617144966Svkashyap
618144966Svkashyap	if (aen_code != TWA_AEN_SYNC_TIME_WITH_HOST) {
619208969Sdelphij		ctlr->internal_req_busy = TW_CL_FALSE;
620144966Svkashyap		tw_cli_req_q_insert_tail(req, TW_CLI_FREE_Q);
621144966Svkashyap		if (aen_code != TWA_AEN_QUEUE_EMPTY)
622144966Svkashyap			if ((error = tw_cli_get_aen(ctlr)))
623144966Svkashyap				tw_cl_create_event(ctlr->ctlr_handle,
624144966Svkashyap					TW_CL_FALSE,
625144966Svkashyap					TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR,
626144966Svkashyap					0x1207, 0x1,
627144966Svkashyap					TW_CL_SEVERITY_ERROR_STRING,
628144966Svkashyap					"Failed to fetch all AEN's",
629144966Svkashyap					"error = %d", error);
630144966Svkashyap	}
631144966Svkashyap}
632144966Svkashyap
633144966Svkashyap
634144966Svkashyap
635144966Svkashyap/*
636144966Svkashyap * Function name:	tw_cli_manage_aen
637144966Svkashyap * Description:		Handles AEN's.
638144966Svkashyap *
639144966Svkashyap * Input:		ctlr	-- ptr to CL internal ctlr context
640144966Svkashyap *			req	-- ptr to CL internal request context
641144966Svkashyap * Output:		None
642144966Svkashyap * Return value:	None
643144966Svkashyap */
644144966SvkashyapTW_UINT16
645144966Svkashyaptw_cli_manage_aen(struct tw_cli_ctlr_context *ctlr,
646144966Svkashyap	struct tw_cli_req_context *req)
647144966Svkashyap{
648144966Svkashyap	struct tw_cl_command_header	*cmd_hdr;
649144966Svkashyap	TW_UINT16			aen_code;
650144966Svkashyap	TW_TIME				local_time;
651144966Svkashyap	TW_TIME				sync_time;
652144966Svkashyap	TW_UINT32			error;
653144966Svkashyap
654144966Svkashyap	tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(), "entered");
655144966Svkashyap
656144966Svkashyap	cmd_hdr = (struct tw_cl_command_header *)(req->data);
657144966Svkashyap	aen_code = cmd_hdr->status_block.error;
658144966Svkashyap
659144966Svkashyap	switch (aen_code) {
660144966Svkashyap	case TWA_AEN_SYNC_TIME_WITH_HOST:
661144966Svkashyap		tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(),
662144966Svkashyap			"Received AEN_SYNC_TIME");
663144966Svkashyap		/*
664144966Svkashyap		 * Free the internal req pkt right here, since
665144966Svkashyap		 * tw_cli_set_param will need it.
666144966Svkashyap		 */
667208969Sdelphij		ctlr->internal_req_busy = TW_CL_FALSE;
668144966Svkashyap		tw_cli_req_q_insert_tail(req, TW_CLI_FREE_Q);
669144966Svkashyap
670144966Svkashyap		/*
671144966Svkashyap		 * We will use a callback in tw_cli_set_param only when
672144966Svkashyap		 * interrupts are enabled and we can expect our callback
673208969Sdelphij		 * to get called.  Setting the get_more_aens
674144966Svkashyap		 * flag will make the callback continue to try to retrieve
675144966Svkashyap		 * more AEN's.
676144966Svkashyap		 */
677208969Sdelphij		if (ctlr->interrupts_enabled)
678208969Sdelphij			ctlr->get_more_aens = TW_CL_TRUE;
679144966Svkashyap		/* Calculate time (in seconds) since last Sunday 12.00 AM. */
680144966Svkashyap		local_time = tw_osl_get_local_time();
681144966Svkashyap		sync_time = (local_time - (3 * 86400)) % 604800;
682144966Svkashyap		if ((error = tw_cli_set_param(ctlr, TWA_PARAM_TIME_TABLE,
683144966Svkashyap				TWA_PARAM_TIME_SCHED_TIME, 4,
684144966Svkashyap				&sync_time,
685208969Sdelphij				(ctlr->interrupts_enabled)
686144966Svkashyap				? tw_cli_param_callback : TW_CL_NULL)))
687144966Svkashyap			tw_cl_create_event(ctlr->ctlr_handle, TW_CL_FALSE,
688144966Svkashyap				TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR,
689144966Svkashyap				0x1208, 0x1, TW_CL_SEVERITY_ERROR_STRING,
690144966Svkashyap				"Unable to sync time with ctlr",
691144966Svkashyap				"error = %d", error);
692144966Svkashyap
693144966Svkashyap		break;
694144966Svkashyap
695144966Svkashyap
696144966Svkashyap	case TWA_AEN_QUEUE_EMPTY:
697144966Svkashyap		tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(),
698144966Svkashyap			"AEN queue empty");
699144966Svkashyap		break;
700144966Svkashyap
701144966Svkashyap
702144966Svkashyap	default:
703144966Svkashyap		/* Queue the event. */
704144966Svkashyap
705144966Svkashyap		tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(),
706144966Svkashyap			"Queueing AEN");
707144966Svkashyap		tw_cli_create_ctlr_event(ctlr,
708144966Svkashyap			TW_CL_MESSAGE_SOURCE_CONTROLLER_EVENT,
709144966Svkashyap			cmd_hdr);
710144966Svkashyap		break;
711144966Svkashyap	} /* switch */
712144966Svkashyap	return(aen_code);
713144966Svkashyap}
714144966Svkashyap
715144966Svkashyap
716144966Svkashyap
717144966Svkashyap/*
718144966Svkashyap * Function name:	tw_cli_enable_interrupts
719144966Svkashyap * Description:		Enables interrupts on the controller
720144966Svkashyap *
721144966Svkashyap * Input:		ctlr	-- ptr to CL internal ctlr context
722144966Svkashyap * Output:		None
723144966Svkashyap * Return value:	None
724144966Svkashyap */
725144966SvkashyapTW_VOID
726144966Svkashyaptw_cli_enable_interrupts(struct tw_cli_ctlr_context *ctlr)
727144966Svkashyap{
728144966Svkashyap	tw_cli_dbg_printf(3, ctlr->ctlr_handle, tw_osl_cur_func(), "entered");
729144966Svkashyap
730208969Sdelphij	ctlr->interrupts_enabled = TW_CL_TRUE;
731144966Svkashyap	TW_CLI_WRITE_CONTROL_REGISTER(ctlr->ctlr_handle,
732144966Svkashyap		TWA_CONTROL_CLEAR_ATTENTION_INTERRUPT |
733144966Svkashyap		TWA_CONTROL_UNMASK_RESPONSE_INTERRUPT |
734144966Svkashyap		TWA_CONTROL_ENABLE_INTERRUPTS);
735144966Svkashyap}
736144966Svkashyap
737144966Svkashyap
738144966Svkashyap
739144966Svkashyap/*
740144966Svkashyap * Function name:	twa_setup
741144966Svkashyap * Description:		Disables interrupts on the controller
742144966Svkashyap *
743144966Svkashyap * Input:		ctlr	-- ptr to CL internal ctlr context
744144966Svkashyap * Output:		None
745144966Svkashyap * Return value:	None
746144966Svkashyap */
747144966SvkashyapTW_VOID
748144966Svkashyaptw_cli_disable_interrupts(struct tw_cli_ctlr_context *ctlr)
749144966Svkashyap{
750144966Svkashyap	tw_cli_dbg_printf(3, ctlr->ctlr_handle, tw_osl_cur_func(), "entered");
751144966Svkashyap
752144966Svkashyap	TW_CLI_WRITE_CONTROL_REGISTER(ctlr->ctlr_handle,
753144966Svkashyap		TWA_CONTROL_DISABLE_INTERRUPTS);
754208969Sdelphij	ctlr->interrupts_enabled = TW_CL_FALSE;
755144966Svkashyap}
756144966Svkashyap
757