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
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
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
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
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
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
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
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
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
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
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
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
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
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
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 }
Cache object: 6deee3ea2f419dc97a715571e04ad8d8
|