xref: /freebsd-12.1/sys/dev/twa/tw_cl_intr.c (revision 718cf2cc)
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 /*
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  */
66 TW_INT32
tw_cl_interrupt(struct tw_cl_ctlr_handle * ctlr_handle)67 tw_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 	}
121 out:
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  */
136 TW_VOID
tw_cli_process_host_intr(struct tw_cli_ctlr_context * ctlr)137 tw_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  */
154 TW_VOID
tw_cli_process_attn_intr(struct tw_cli_ctlr_context * ctlr)155 tw_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  */
190 TW_VOID
tw_cli_process_cmd_intr(struct tw_cli_ctlr_context * ctlr)191 tw_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  */
217 TW_INT32
tw_cli_process_resp_intr(struct tw_cli_ctlr_context * ctlr)218 tw_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  */
283 TW_INT32
tw_cli_submit_pending_queue(struct tw_cli_ctlr_context * ctlr)284 tw_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  */
353 TW_VOID
tw_cli_process_complete_queue(struct tw_cli_ctlr_context * ctlr)354 tw_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  */
381 TW_VOID
tw_cli_complete_io(struct tw_cli_req_context * req)382 tw_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 
416 out:
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  */
431 TW_VOID
tw_cli_scsi_complete(struct tw_cli_req_context * req)432 tw_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  */
518 TW_VOID
tw_cli_param_callback(struct tw_cli_req_context * req)519 tw_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  */
572 TW_VOID
tw_cli_aen_callback(struct tw_cli_req_context * req)573 tw_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  */
646 TW_UINT16
tw_cli_manage_aen(struct tw_cli_ctlr_context * ctlr,struct tw_cli_req_context * req)647 tw_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  */
727 TW_VOID
tw_cli_enable_interrupts(struct tw_cli_ctlr_context * ctlr)728 tw_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  */
749 TW_VOID
tw_cli_disable_interrupts(struct tw_cli_ctlr_context * ctlr)750 tw_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