xref: /freebsd-13.1/sys/dev/twa/tw_cl_intr.c (revision bed02296)
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  */
62 TW_INT32
tw_cl_interrupt(struct tw_cl_ctlr_handle * ctlr_handle)63 tw_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 	}
117 out:
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  */
130 TW_VOID
tw_cli_process_host_intr(struct tw_cli_ctlr_context * ctlr)131 tw_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  */
146 TW_VOID
tw_cli_process_attn_intr(struct tw_cli_ctlr_context * ctlr)147 tw_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  */
180 TW_VOID
tw_cli_process_cmd_intr(struct tw_cli_ctlr_context * ctlr)181 tw_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  */
205 TW_INT32
tw_cli_process_resp_intr(struct tw_cli_ctlr_context * ctlr)206 tw_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  */
268 TW_INT32
tw_cli_submit_pending_queue(struct tw_cli_ctlr_context * ctlr)269 tw_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  */
336 TW_VOID
tw_cli_process_complete_queue(struct tw_cli_ctlr_context * ctlr)337 tw_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  */
362 TW_VOID
tw_cli_complete_io(struct tw_cli_req_context * req)363 tw_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 
397 out:
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  */
410 TW_VOID
tw_cli_scsi_complete(struct tw_cli_req_context * req)411 tw_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  */
495 TW_VOID
tw_cli_param_callback(struct tw_cli_req_context * req)496 tw_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  */
547 TW_VOID
tw_cli_aen_callback(struct tw_cli_req_context * req)548 tw_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  */
619 TW_UINT16
tw_cli_manage_aen(struct tw_cli_ctlr_context * ctlr,struct tw_cli_req_context * req)620 tw_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  */
696 TW_VOID
tw_cli_enable_interrupts(struct tw_cli_ctlr_context * ctlr)697 tw_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  */
716 TW_VOID
tw_cli_disable_interrupts(struct tw_cli_ctlr_context * ctlr)717 tw_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