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: releng/12.0/sys/dev/twa/tw_cl_intr.c 326255 2017-11-27 14:52:40Z pfg $
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
Cache object: a65972acd5b3d9f459c5a520b0de2294
|