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