1/*-
2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3 *
4 * Copyright (c) 2004-07 Applied Micro Circuits Corporation.
5 * Copyright (c) 2004-05 Vinod Kashyap
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 *
29 *	$FreeBSD$
30 */
31
32/*
33 * AMCC'S 3ware driver for 9000 series storage controllers.
34 *
35 * Author: Vinod Kashyap
36 * Modifications by: Adam Radford
37 * Modifications by: Manjunath Ranganathaiah
38 */
39
40/*
41 * Common Layer interrupt handling functions.
42 */
43
44#include "tw_osl_share.h"
45#include "tw_cl_share.h"
46#include "tw_cl_fwif.h"
47#include "tw_cl_ioctl.h"
48#include "tw_cl.h"
49#include "tw_cl_externs.h"
50#include "tw_osl_ioctl.h"
51
52/*
53 * Function name:	twa_interrupt
54 * Description:		Interrupt handler.  Determines the kind of interrupt,
55 *			and returns TW_CL_TRUE if it recognizes the interrupt.
56 *
57 * Input:		ctlr_handle	-- controller handle
58 * Output:		None
59 * Return value:	TW_CL_TRUE -- interrupt recognized
60 *			TW_CL_FALSE-- interrupt not recognized
61 */
62TW_INT32
63tw_cl_interrupt(struct tw_cl_ctlr_handle *ctlr_handle)
64{
65	struct tw_cli_ctlr_context	*ctlr =
66		(struct tw_cli_ctlr_context *)(ctlr_handle->cl_ctlr_ctxt);
67	TW_UINT32			status_reg;
68	TW_INT32			rc = TW_CL_FALSE;
69
70	tw_cli_dbg_printf(10, ctlr_handle, tw_osl_cur_func(), "entered");
71
72	/* If we don't have controller context, bail */
73	if (ctlr == NULL)
74		goto out;
75
76	/*
77	 * Bail If we get an interrupt while resetting, or shutting down.
78	 */
79	if (ctlr->reset_in_progress || !(ctlr->active))
80		goto out;
81
82	/* Read the status register to determine the type of interrupt. */
83	status_reg = TW_CLI_READ_STATUS_REGISTER(ctlr_handle);
84	if (tw_cli_check_ctlr_state(ctlr, status_reg))
85		goto out;
86
87	/* Clear the interrupt. */
88	if (status_reg & TWA_STATUS_HOST_INTERRUPT) {
89		tw_cli_dbg_printf(6, ctlr_handle, tw_osl_cur_func(),
90			"Host interrupt");
91		TW_CLI_WRITE_CONTROL_REGISTER(ctlr_handle,
92			TWA_CONTROL_CLEAR_HOST_INTERRUPT);
93	}
94	if (status_reg & TWA_STATUS_ATTENTION_INTERRUPT) {
95		tw_cli_dbg_printf(6, ctlr_handle, tw_osl_cur_func(),
96			"Attention interrupt");
97		rc |= TW_CL_TRUE; /* request for a deferred isr call */
98		tw_cli_process_attn_intr(ctlr);
99		TW_CLI_WRITE_CONTROL_REGISTER(ctlr_handle,
100			TWA_CONTROL_CLEAR_ATTENTION_INTERRUPT);
101	}
102	if (status_reg & TWA_STATUS_COMMAND_INTERRUPT) {
103		tw_cli_dbg_printf(6, ctlr_handle, tw_osl_cur_func(),
104			"Command interrupt");
105		rc |= TW_CL_TRUE; /* request for a deferred isr call */
106		tw_cli_process_cmd_intr(ctlr);
107		if ((TW_CL_Q_FIRST_ITEM(&(ctlr->req_q_head[TW_CLI_PENDING_Q]))) == TW_CL_NULL)
108			TW_CLI_WRITE_CONTROL_REGISTER(ctlr_handle,
109				TWA_CONTROL_MASK_COMMAND_INTERRUPT);
110	}
111	if (status_reg & TWA_STATUS_RESPONSE_INTERRUPT) {
112		tw_cli_dbg_printf(10, ctlr_handle, tw_osl_cur_func(),
113			"Response interrupt");
114		rc |= TW_CL_TRUE; /* request for a deferred isr call */
115		tw_cli_process_resp_intr(ctlr);
116	}
117out:
118	return(rc);
119}
120
121/*
122 * Function name:	tw_cli_process_host_intr
123 * Description:		This function gets called if we triggered an interrupt.
124 *			We don't use it as of now.
125 *
126 * Input:		ctlr	-- ptr to CL internal ctlr context
127 * Output:		None
128 * Return value:	None
129 */
130TW_VOID
131tw_cli_process_host_intr(struct tw_cli_ctlr_context *ctlr)
132{
133	tw_cli_dbg_printf(6, ctlr->ctlr_handle, tw_osl_cur_func(), "entered");
134}
135
136/*
137 * Function name:	tw_cli_process_attn_intr
138 * Description:		This function gets called if the fw posted an AEN
139 *			(Asynchronous Event Notification).  It fetches
140 *			all the AEN's that the fw might have posted.
141 *
142 * Input:		ctlr	-- ptr to CL internal ctlr context
143 * Output:		None
144 * Return value:	None
145 */
146TW_VOID
147tw_cli_process_attn_intr(struct tw_cli_ctlr_context *ctlr)
148{
149	TW_INT32	error;
150
151	tw_cli_dbg_printf(6, ctlr->ctlr_handle, tw_osl_cur_func(), "entered");
152
153	if ((error = tw_cli_get_aen(ctlr))) {
154		/*
155		 * If the driver is already in the process of retrieveing AEN's,
156		 * we will be returned TW_OSL_EBUSY.  In this case,
157		 * tw_cli_param_callback or tw_cli_aen_callback will eventually
158		 * retrieve the AEN this attention interrupt is for.  So, we
159		 * don't need to print the failure.
160		 */
161		if (error != TW_OSL_EBUSY)
162			tw_cl_create_event(ctlr->ctlr_handle, TW_CL_FALSE,
163				TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR,
164				0x1200, 0x1, TW_CL_SEVERITY_ERROR_STRING,
165				"Failed to fetch AEN",
166				"error = %d", error);
167	}
168}
169
170/*
171 * Function name:	tw_cli_process_cmd_intr
172 * Description:		This function gets called if we hit a queue full
173 *			condition earlier, and the fw is now ready for
174 *			new cmds.  Submits any pending requests.
175 *
176 * Input:		ctlr	-- ptr to CL internal ctlr context
177 * Output:		None
178 * Return value:	None
179 */
180TW_VOID
181tw_cli_process_cmd_intr(struct tw_cli_ctlr_context *ctlr)
182{
183	tw_cli_dbg_printf(6, ctlr->ctlr_handle, tw_osl_cur_func(), "entered");
184
185	/* Start any requests that might be in the pending queue. */
186	tw_cli_submit_pending_queue(ctlr);
187
188	/*
189	 * If tw_cli_submit_pending_queue was unsuccessful due to a "cmd queue
190	 * full" condition, cmd_intr will already have been unmasked by
191	 * tw_cli_submit_cmd.  We don't need to do it again... simply return.
192	 */
193}
194
195/*
196 * Function name:	tw_cli_process_resp_intr
197 * Description:		Looks for cmd completions from fw; queues cmds completed
198 *			by fw into complete queue.
199 *
200 * Input:		ctlr	-- ptr to CL internal ctlr context
201 * Output:		None
202 * Return value:	0	-- no ctlr error
203 *			non-zero-- ctlr error
204 */
205TW_INT32
206tw_cli_process_resp_intr(struct tw_cli_ctlr_context *ctlr)
207{
208	TW_UINT32			resp;
209	struct tw_cli_req_context	*req;
210	TW_INT32			error;
211	TW_UINT32			status_reg;
212
213	tw_cli_dbg_printf(10, ctlr->ctlr_handle, tw_osl_cur_func(), "entered");
214
215	for (;;) {
216		status_reg = TW_CLI_READ_STATUS_REGISTER(ctlr->ctlr_handle);
217		if ((error = tw_cli_check_ctlr_state(ctlr, status_reg)))
218			break;
219		if (status_reg & TWA_STATUS_RESPONSE_QUEUE_EMPTY) {
220			tw_cli_dbg_printf(7, ctlr->ctlr_handle,
221				tw_osl_cur_func(), "Response queue empty");
222			break;
223		}
224
225		/* Response queue is not empty. */
226		resp = TW_CLI_READ_RESPONSE_QUEUE(ctlr->ctlr_handle);
227		{
228			req = &(ctlr->req_ctxt_buf[GET_RESP_ID(resp)]);
229		}
230
231		if (req->state != TW_CLI_REQ_STATE_BUSY) {
232			tw_cl_create_event(ctlr->ctlr_handle, TW_CL_FALSE,
233				TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR,
234				0x1201, 0x1, TW_CL_SEVERITY_ERROR_STRING,
235				"Unposted command completed!!",
236				"request = %p, status = %d",
237				req, req->state);
238#ifdef TW_OSL_DEBUG
239			tw_cl_print_ctlr_stats(ctlr->ctlr_handle);
240#endif /* TW_OSL_DEBUG */
241			continue;
242		}
243
244		/*
245		 * Remove the request from the busy queue, mark it as complete,
246		 * and enqueue it in the complete queue.
247		 */
248		tw_cli_req_q_remove_item(req, TW_CLI_BUSY_Q);
249		req->state = TW_CLI_REQ_STATE_COMPLETE;
250		tw_cli_req_q_insert_tail(req, TW_CLI_COMPLETE_Q);
251	}
252
253	/* Complete this, and other requests in the complete queue. */
254	tw_cli_process_complete_queue(ctlr);
255
256	return(error);
257}
258
259/*
260 * Function name:	tw_cli_submit_pending_queue
261 * Description:		Kick starts any requests in the pending queue.
262 *
263 * Input:		ctlr	-- ptr to CL internal ctlr context
264 * Output:		None
265 * Return value:	0	-- all pending requests submitted successfully
266 *			non-zero-- otherwise
267 */
268TW_INT32
269tw_cli_submit_pending_queue(struct tw_cli_ctlr_context *ctlr)
270{
271	struct tw_cli_req_context	*req;
272	TW_INT32			error = TW_OSL_ESUCCESS;
273
274	tw_cli_dbg_printf(3, ctlr->ctlr_handle, tw_osl_cur_func(), "entered");
275
276	/*
277	 * Pull requests off the pending queue, and submit them.
278	 */
279	while ((req = tw_cli_req_q_remove_head(ctlr, TW_CLI_PENDING_Q)) !=
280		TW_CL_NULL) {
281		if ((error = tw_cli_submit_cmd(req))) {
282			if (error == TW_OSL_EBUSY) {
283				tw_cli_dbg_printf(2, ctlr->ctlr_handle,
284					tw_osl_cur_func(),
285					"Requeueing pending request");
286				req->state = TW_CLI_REQ_STATE_PENDING;
287				/*
288				 * Queue the request at the head of the pending
289				 * queue, and break away, so we don't try to
290				 * submit any more requests.
291				 */
292				tw_cli_req_q_insert_head(req, TW_CLI_PENDING_Q);
293				break;
294			} else {
295				tw_cl_create_event(ctlr->ctlr_handle,
296					TW_CL_FALSE,
297					TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR,
298					0x1202, 0x1,
299					TW_CL_SEVERITY_ERROR_STRING,
300					"Could not start request "
301					"in pending queue",
302					"request = %p, opcode = 0x%x, "
303					"error = %d", req,
304					GET_OPCODE(req->cmd_pkt->
305						command.cmd_pkt_9k.res__opcode),
306					error);
307				/*
308				 * Set the appropriate error and call the CL
309				 * internal callback if there's one.  If the
310				 * request originator is polling for completion,
311				 * he should be checking req->error to
312				 * determine that the request did not go
313				 * through.  The request originators are
314				 * responsible for the clean-up.
315				 */
316				req->error_code = error;
317				req->state = TW_CLI_REQ_STATE_COMPLETE;
318				if (req->tw_cli_callback)
319					req->tw_cli_callback(req);
320				error = TW_OSL_ESUCCESS;
321			}
322		}
323	}
324	return(error);
325}
326
327/*
328 * Function name:	tw_cli_process_complete_queue
329 * Description:		Calls the CL internal callback routine, if any, for
330 *			each request in the complete queue.
331 *
332 * Input:		ctlr	-- ptr to CL internal ctlr context
333 * Output:		None
334 * Return value:	None
335 */
336TW_VOID
337tw_cli_process_complete_queue(struct tw_cli_ctlr_context *ctlr)
338{
339	struct tw_cli_req_context	*req;
340
341	tw_cli_dbg_printf(10, ctlr->ctlr_handle, tw_osl_cur_func(), "entered");
342
343	/*
344	 * Pull commands off the completed list, dispatch them appropriately.
345	 */
346	while ((req = tw_cli_req_q_remove_head(ctlr, TW_CLI_COMPLETE_Q)) !=
347		TW_CL_NULL) {
348		/* Call the CL internal callback, if there's one. */
349		if (req->tw_cli_callback)
350			req->tw_cli_callback(req);
351	}
352}
353
354/*
355 * Function name:	tw_cli_complete_io
356 * Description:		CL internal callback for SCSI/fw passthru requests.
357 *
358 * Input:		req	-- ptr to CL internal request context
359 * Output:		None
360 * Return value:	None
361 */
362TW_VOID
363tw_cli_complete_io(struct tw_cli_req_context *req)
364{
365	struct tw_cli_ctlr_context	*ctlr = req->ctlr;
366	struct tw_cl_req_packet		*req_pkt =
367		(struct tw_cl_req_packet *)(req->orig_req);
368
369	tw_cli_dbg_printf(8, ctlr->ctlr_handle, tw_osl_cur_func(), "entered");
370
371	req_pkt->status = TW_CL_ERR_REQ_SUCCESS;
372	if (req->error_code) {
373		req_pkt->status = TW_CL_ERR_REQ_UNABLE_TO_SUBMIT_COMMAND;
374		goto out;
375	}
376
377	if (req->state != TW_CLI_REQ_STATE_COMPLETE) {
378		tw_cl_create_event(ctlr->ctlr_handle, TW_CL_FALSE,
379			TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR,
380			0x1203, 0x1, TW_CL_SEVERITY_ERROR_STRING,
381			"I/O completion on incomplete command!!",
382			"request = %p, status = %d",
383			req, req->state);
384#ifdef TW_OSL_DEBUG
385		tw_cl_print_ctlr_stats(ctlr->ctlr_handle);
386#endif /* TW_OSL_DEBUG */
387		return;
388	}
389
390	if (req->flags & TW_CLI_REQ_FLAGS_PASSTHRU) {
391		/* Copy the command packet back into OSL's space. */
392		tw_osl_memcpy(req_pkt->gen_req_pkt.pt_req.cmd_pkt, req->cmd_pkt,
393			sizeof(struct tw_cl_command_packet));
394	} else
395		tw_cli_scsi_complete(req);
396
397out:
398	req_pkt->tw_osl_callback(req->req_handle);
399	tw_cli_req_q_insert_tail(req, TW_CLI_FREE_Q);
400}
401
402/*
403 * Function name:	tw_cli_scsi_complete
404 * Description:		Completion routine for SCSI requests.
405 *
406 * Input:		req	-- ptr to CL internal request context
407 * Output:		None
408 * Return value:	None
409 */
410TW_VOID
411tw_cli_scsi_complete(struct tw_cli_req_context *req)
412{
413	struct tw_cl_req_packet		*req_pkt =
414		(struct tw_cl_req_packet *)(req->orig_req);
415	struct tw_cl_scsi_req_packet	*scsi_req =
416		&(req_pkt->gen_req_pkt.scsi_req);
417	struct tw_cl_command_9k		*cmd =
418		&(req->cmd_pkt->command.cmd_pkt_9k);
419	struct tw_cl_command_header	*cmd_hdr;
420	TW_UINT16			error;
421	TW_UINT8			*cdb;
422
423	tw_cli_dbg_printf(8, req->ctlr->ctlr_handle, tw_osl_cur_func(),
424		"entered");
425
426	scsi_req->scsi_status = cmd->status;
427	if (! cmd->status)
428		return;
429
430	tw_cli_dbg_printf(1, req->ctlr->ctlr_handle, tw_osl_cur_func(),
431		"req_id = 0x%x, status = 0x%x",
432		GET_REQ_ID(cmd->lun_l4__req_id), cmd->status);
433
434	cmd_hdr = &(req->cmd_pkt->cmd_hdr);
435	error = cmd_hdr->status_block.error;
436	if ((error == TWA_ERROR_LOGICAL_UNIT_NOT_SUPPORTED) ||
437			(error == TWA_ERROR_UNIT_OFFLINE)) {
438		if (GET_LUN_L4(cmd->lun_l4__req_id))
439			req_pkt->status |= TW_CL_ERR_REQ_INVALID_LUN;
440		else
441			req_pkt->status |= TW_CL_ERR_REQ_INVALID_TARGET;
442	} else {
443		tw_cli_dbg_printf(2, req->ctlr->ctlr_handle,
444			tw_osl_cur_func(),
445			"cmd = %x %x %x %x %x %x %x",
446			GET_OPCODE(cmd->res__opcode),
447			GET_SGL_OFF(cmd->res__opcode),
448			cmd->unit,
449			cmd->lun_l4__req_id,
450			cmd->status,
451			cmd->sgl_offset,
452			cmd->lun_h4__sgl_entries);
453
454		cdb = (TW_UINT8 *)(cmd->cdb);
455		tw_cli_dbg_printf(2, req->ctlr->ctlr_handle,
456			tw_osl_cur_func(),
457			"cdb = %x %x %x %x %x %x %x %x "
458			"%x %x %x %x %x %x %x %x",
459			cdb[0], cdb[1], cdb[2], cdb[3],
460			cdb[4], cdb[5], cdb[6], cdb[7],
461			cdb[8], cdb[9], cdb[10], cdb[11],
462			cdb[12], cdb[13], cdb[14], cdb[15]);
463
464#if       0
465		/*
466		 * Print the error. Firmware doesn't yet support
467		 * the 'Mode Sense' cmd.  Don't print if the cmd
468		 * is 'Mode Sense', and the error is 'Invalid field
469		 * in CDB'.
470		 */
471		if (! ((cdb[0] == 0x1A) && (error == 0x10D)))
472			tw_cli_create_ctlr_event(req->ctlr,
473				TW_CL_MESSAGE_SOURCE_CONTROLLER_ERROR,
474				cmd_hdr);
475#endif // 0
476	}
477
478	if (scsi_req->sense_data) {
479		tw_osl_memcpy(scsi_req->sense_data, cmd_hdr->sense_data,
480			TWA_SENSE_DATA_LENGTH);
481		scsi_req->sense_len = TWA_SENSE_DATA_LENGTH;
482		req_pkt->status |= TW_CL_ERR_REQ_AUTO_SENSE_VALID;
483	}
484	req_pkt->status |= TW_CL_ERR_REQ_SCSI_ERROR;
485}
486
487/*
488 * Function name:	tw_cli_param_callback
489 * Description:		Callback for get/set_param requests.
490 *
491 * Input:		req	-- ptr to completed request pkt
492 * Output:		None
493 * Return value:	None
494 */
495TW_VOID
496tw_cli_param_callback(struct tw_cli_req_context *req)
497{
498	struct tw_cli_ctlr_context	*ctlr = req->ctlr;
499	union tw_cl_command_7k		*cmd =
500		&(req->cmd_pkt->command.cmd_pkt_7k);
501	TW_INT32			error;
502
503	tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(), "entered");
504
505	/*
506	 * If the request was never submitted to the controller, the function
507	 * that sets req->error is responsible for calling tw_cl_create_event.
508	 */
509	if (! req->error_code)
510		if (cmd->param.status) {
511#if       0
512			tw_cli_create_ctlr_event(ctlr,
513				TW_CL_MESSAGE_SOURCE_CONTROLLER_ERROR,
514				&(req->cmd_pkt->cmd_hdr));
515#endif // 0
516			tw_cl_create_event(ctlr->ctlr_handle, TW_CL_FALSE,
517				TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR,
518				0x1204, 0x1, TW_CL_SEVERITY_ERROR_STRING,
519				"get/set_param failed",
520				"status = %d", cmd->param.status);
521		}
522
523	ctlr->internal_req_busy = TW_CL_FALSE;
524	tw_cli_req_q_insert_tail(req, TW_CLI_FREE_Q);
525
526	if ((ctlr->get_more_aens) && (!(ctlr->reset_in_progress))) {
527		ctlr->get_more_aens = TW_CL_FALSE;
528		tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(),
529			"Fetching more AEN's");
530		if ((error = tw_cli_get_aen(ctlr)))
531			tw_cl_create_event(ctlr->ctlr_handle, TW_CL_FALSE,
532				TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR,
533				0x1205, 0x1, TW_CL_SEVERITY_ERROR_STRING,
534				"Failed to fetch all AEN's from param_callback",
535				"error = %d", error);
536	}
537}
538
539/*
540 * Function name:	tw_cli_aen_callback
541 * Description:		Callback for requests to fetch AEN's.
542 *
543 * Input:		req	-- ptr to completed request pkt
544 * Output:		None
545 * Return value:	None
546 */
547TW_VOID
548tw_cli_aen_callback(struct tw_cli_req_context *req)
549{
550	struct tw_cli_ctlr_context	*ctlr = req->ctlr;
551	struct tw_cl_command_header	*cmd_hdr;
552	struct tw_cl_command_9k		*cmd =
553		&(req->cmd_pkt->command.cmd_pkt_9k);
554	TW_UINT16			aen_code = TWA_AEN_QUEUE_EMPTY;
555	TW_INT32			error;
556
557	tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(), "entered");
558
559	tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(),
560		"req_id = 0x%x, req error = %d, status = 0x%x",
561		GET_REQ_ID(cmd->lun_l4__req_id), req->error_code, cmd->status);
562
563	/*
564	 * If the request was never submitted to the controller, the function
565	 * that sets error is responsible for calling tw_cl_create_event.
566	 */
567	if (!(error = req->error_code))
568		if ((error = cmd->status)) {
569			cmd_hdr = (struct tw_cl_command_header *)
570				(&(req->cmd_pkt->cmd_hdr));
571#if       0
572			tw_cli_create_ctlr_event(ctlr,
573				TW_CL_MESSAGE_SOURCE_CONTROLLER_ERROR,
574				cmd_hdr);
575#endif // 0
576			tw_cl_create_event(ctlr->ctlr_handle, TW_CL_FALSE,
577				TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR,
578				0x1206, 0x1, TW_CL_SEVERITY_ERROR_STRING,
579				"Request Sense failed",
580				"opcode = 0x%x, status = %d",
581				GET_OPCODE(cmd->res__opcode), cmd->status);
582		}
583
584	if (error) {
585		ctlr->internal_req_busy = TW_CL_FALSE;
586		tw_cli_req_q_insert_tail(req, TW_CLI_FREE_Q);
587		return;
588	}
589
590	tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(),
591		"Request Sense command succeeded");
592
593	aen_code = tw_cli_manage_aen(ctlr, req);
594
595	if (aen_code != TWA_AEN_SYNC_TIME_WITH_HOST) {
596		ctlr->internal_req_busy = TW_CL_FALSE;
597		tw_cli_req_q_insert_tail(req, TW_CLI_FREE_Q);
598		if (aen_code != TWA_AEN_QUEUE_EMPTY)
599			if ((error = tw_cli_get_aen(ctlr)))
600				tw_cl_create_event(ctlr->ctlr_handle,
601					TW_CL_FALSE,
602					TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR,
603					0x1207, 0x1,
604					TW_CL_SEVERITY_ERROR_STRING,
605					"Failed to fetch all AEN's",
606					"error = %d", error);
607	}
608}
609
610/*
611 * Function name:	tw_cli_manage_aen
612 * Description:		Handles AEN's.
613 *
614 * Input:		ctlr	-- ptr to CL internal ctlr context
615 *			req	-- ptr to CL internal request context
616 * Output:		None
617 * Return value:	None
618 */
619TW_UINT16
620tw_cli_manage_aen(struct tw_cli_ctlr_context *ctlr,
621	struct tw_cli_req_context *req)
622{
623	struct tw_cl_command_header	*cmd_hdr;
624	TW_UINT16			aen_code;
625	TW_TIME				local_time;
626	TW_TIME				sync_time;
627	TW_UINT32			error;
628
629	tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(), "entered");
630
631	cmd_hdr = (struct tw_cl_command_header *)(req->data);
632	aen_code = cmd_hdr->status_block.error;
633
634	switch (aen_code) {
635	case TWA_AEN_SYNC_TIME_WITH_HOST:
636		tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(),
637			"Received AEN_SYNC_TIME");
638		/*
639		 * Free the internal req pkt right here, since
640		 * tw_cli_set_param will need it.
641		 */
642		ctlr->internal_req_busy = TW_CL_FALSE;
643		tw_cli_req_q_insert_tail(req, TW_CLI_FREE_Q);
644
645		/*
646		 * We will use a callback in tw_cli_set_param only when
647		 * interrupts are enabled and we can expect our callback
648		 * to get called.  Setting the get_more_aens
649		 * flag will make the callback continue to try to retrieve
650		 * more AEN's.
651		 */
652		if (ctlr->interrupts_enabled)
653			ctlr->get_more_aens = TW_CL_TRUE;
654		/* Calculate time (in seconds) since last Sunday 12.00 AM. */
655		local_time = tw_osl_get_local_time();
656		sync_time = (local_time - (3 * 86400)) % 604800;
657		if ((error = tw_cli_set_param(ctlr, TWA_PARAM_TIME_TABLE,
658				TWA_PARAM_TIME_SCHED_TIME, 4,
659				&sync_time,
660				(ctlr->interrupts_enabled)
661				? tw_cli_param_callback : TW_CL_NULL)))
662			tw_cl_create_event(ctlr->ctlr_handle, TW_CL_FALSE,
663				TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR,
664				0x1208, 0x1, TW_CL_SEVERITY_ERROR_STRING,
665				"Unable to sync time with ctlr",
666				"error = %d", error);
667
668		break;
669
670	case TWA_AEN_QUEUE_EMPTY:
671		tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(),
672			"AEN queue empty");
673		break;
674
675	default:
676		/* Queue the event. */
677
678		tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(),
679			"Queueing AEN");
680		tw_cli_create_ctlr_event(ctlr,
681			TW_CL_MESSAGE_SOURCE_CONTROLLER_EVENT,
682			cmd_hdr);
683		break;
684	} /* switch */
685	return(aen_code);
686}
687
688/*
689 * Function name:	tw_cli_enable_interrupts
690 * Description:		Enables interrupts on the controller
691 *
692 * Input:		ctlr	-- ptr to CL internal ctlr context
693 * Output:		None
694 * Return value:	None
695 */
696TW_VOID
697tw_cli_enable_interrupts(struct tw_cli_ctlr_context *ctlr)
698{
699	tw_cli_dbg_printf(3, ctlr->ctlr_handle, tw_osl_cur_func(), "entered");
700
701	ctlr->interrupts_enabled = TW_CL_TRUE;
702	TW_CLI_WRITE_CONTROL_REGISTER(ctlr->ctlr_handle,
703		TWA_CONTROL_CLEAR_ATTENTION_INTERRUPT |
704		TWA_CONTROL_UNMASK_RESPONSE_INTERRUPT |
705		TWA_CONTROL_ENABLE_INTERRUPTS);
706}
707
708/*
709 * Function name:	twa_setup
710 * Description:		Disables interrupts on the controller
711 *
712 * Input:		ctlr	-- ptr to CL internal ctlr context
713 * Output:		None
714 * Return value:	None
715 */
716TW_VOID
717tw_cli_disable_interrupts(struct tw_cli_ctlr_context *ctlr)
718{
719	tw_cli_dbg_printf(3, ctlr->ctlr_handle, tw_osl_cur_func(), "entered");
720
721	TW_CLI_WRITE_CONTROL_REGISTER(ctlr->ctlr_handle,
722		TWA_CONTROL_DISABLE_INTERRUPTS);
723	ctlr->interrupts_enabled = TW_CL_FALSE;
724}
725