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