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