2 * Copyright (c) 2004-07 Applied Micro Circuits Corporation.
3 * Copyright (c) 2004-05 Vinod Kashyap
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
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.
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
31 * AMCC'S 3ware driver for 9000 series storage controllers.
33 * Author: Vinod Kashyap
34 * Modifications by: Adam Radford
35 * Modifications by: Manjunath Ranganathaiah
40 * Common Layer interrupt handling functions.
44 #include "tw_osl_share.h"
45 #include "tw_cl_share.h"
46 #include "tw_cl_fwif.h"
47 #include "tw_cl_ioctl.h"
49 #include "tw_cl_externs.h"
50 #include "tw_osl_ioctl.h"
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.
59 * Input: ctlr_handle -- controller handle
61 * Return value: TW_CL_TRUE -- interrupt recognized
62 * TW_CL_FALSE-- interrupt not recognized
65 tw_cl_interrupt(struct tw_cl_ctlr_handle *ctlr_handle)
67 struct tw_cli_ctlr_context *ctlr =
68 (struct tw_cli_ctlr_context *)(ctlr_handle->cl_ctlr_ctxt);
70 TW_INT32 rc = TW_CL_FALSE;
72 tw_cli_dbg_printf(10, ctlr_handle, tw_osl_cur_func(), "entered");
74 /* If we don't have controller context, bail */
78 /* If we get an interrupt while resetting, it is a shared
79 one for another device, so just bail */
80 if (ctlr->state & TW_CLI_CTLR_STATE_RESET_IN_PROGRESS)
84 * Synchronize access between writes to command and control registers
85 * in 64-bit environments, on G66.
87 if (ctlr->state & TW_CLI_CTLR_STATE_G66_WORKAROUND_NEEDED)
88 tw_osl_get_lock(ctlr_handle, ctlr->io_lock);
90 /* Read the status register to determine the type of interrupt. */
91 status_reg = TW_CLI_READ_STATUS_REGISTER(ctlr_handle);
92 if (tw_cli_check_ctlr_state(ctlr, status_reg))
95 /* Clear the interrupt. */
96 if (status_reg & TWA_STATUS_HOST_INTERRUPT) {
97 tw_cli_dbg_printf(6, ctlr_handle, tw_osl_cur_func(),
99 TW_CLI_WRITE_CONTROL_REGISTER(ctlr_handle,
100 TWA_CONTROL_CLEAR_HOST_INTERRUPT);
101 ctlr->host_intr_pending = 0; /* we don't use this */
102 rc |= TW_CL_FALSE; /* don't request for a deferred isr call */
104 if (status_reg & TWA_STATUS_ATTENTION_INTERRUPT) {
105 tw_cli_dbg_printf(6, ctlr_handle, tw_osl_cur_func(),
106 "Attention interrupt");
107 TW_CLI_WRITE_CONTROL_REGISTER(ctlr_handle,
108 TWA_CONTROL_CLEAR_ATTENTION_INTERRUPT);
109 ctlr->attn_intr_pending = 1;
110 rc |= TW_CL_TRUE; /* request for a deferred isr call */
112 if (status_reg & TWA_STATUS_COMMAND_INTERRUPT) {
113 tw_cli_dbg_printf(6, ctlr_handle, tw_osl_cur_func(),
114 "Command interrupt");
115 TW_CLI_WRITE_CONTROL_REGISTER(ctlr_handle,
116 TWA_CONTROL_MASK_COMMAND_INTERRUPT);
117 ctlr->cmd_intr_pending = 1;
118 rc |= TW_CL_TRUE; /* request for a deferred isr call */
120 if (status_reg & TWA_STATUS_RESPONSE_INTERRUPT) {
121 tw_cli_dbg_printf(10, ctlr_handle, tw_osl_cur_func(),
122 "Response interrupt");
123 TW_CLI_WRITE_CONTROL_REGISTER(ctlr_handle,
124 TWA_CONTROL_MASK_RESPONSE_INTERRUPT);
125 ctlr->resp_intr_pending = 1;
126 rc |= TW_CL_TRUE; /* request for a deferred isr call */
129 if (ctlr->state & TW_CLI_CTLR_STATE_G66_WORKAROUND_NEEDED)
130 tw_osl_free_lock(ctlr_handle, ctlr->io_lock);
138 * Function name: tw_cl_deferred_interrupt
139 * Description: Deferred interrupt handler. Does most of the processing
140 * related to an interrupt.
142 * Input: ctlr_handle -- controller handle
147 tw_cl_deferred_interrupt(struct tw_cl_ctlr_handle *ctlr_handle)
149 struct tw_cli_ctlr_context *ctlr =
150 (struct tw_cli_ctlr_context *)(ctlr_handle->cl_ctlr_ctxt);
152 tw_cli_dbg_printf(10, ctlr_handle, tw_osl_cur_func(), "entered");
154 /* Dispatch based on the kind of interrupt. */
155 if (ctlr->host_intr_pending) {
156 tw_cli_dbg_printf(6, ctlr_handle, tw_osl_cur_func(),
157 "Processing Host interrupt");
158 ctlr->host_intr_pending = 0;
159 tw_cli_process_host_intr(ctlr);
161 if (ctlr->attn_intr_pending) {
162 tw_cli_dbg_printf(6, ctlr_handle, tw_osl_cur_func(),
163 "Processing Attention interrupt");
164 ctlr->attn_intr_pending = 0;
165 tw_cli_process_attn_intr(ctlr);
167 if (ctlr->cmd_intr_pending) {
168 tw_cli_dbg_printf(6, ctlr_handle, tw_osl_cur_func(),
169 "Processing Command interrupt");
170 ctlr->cmd_intr_pending = 0;
171 tw_cli_process_cmd_intr(ctlr);
173 if (ctlr->resp_intr_pending) {
174 tw_cli_dbg_printf(10, ctlr_handle, tw_osl_cur_func(),
175 "Processing Response interrupt");
176 ctlr->resp_intr_pending = 0;
177 tw_cli_process_resp_intr(ctlr);
184 * Function name: tw_cli_process_host_intr
185 * Description: This function gets called if we triggered an interrupt.
186 * We don't use it as of now.
188 * Input: ctlr -- ptr to CL internal ctlr context
193 tw_cli_process_host_intr(struct tw_cli_ctlr_context *ctlr)
195 tw_cli_dbg_printf(6, ctlr->ctlr_handle, tw_osl_cur_func(), "entered");
201 * Function name: tw_cli_process_attn_intr
202 * Description: This function gets called if the fw posted an AEN
203 * (Asynchronous Event Notification). It fetches
204 * all the AEN's that the fw might have posted.
206 * Input: ctlr -- ptr to CL internal ctlr context
211 tw_cli_process_attn_intr(struct tw_cli_ctlr_context *ctlr)
215 tw_cli_dbg_printf(6, ctlr->ctlr_handle, tw_osl_cur_func(), "entered");
217 if ((error = tw_cli_get_aen(ctlr))) {
219 * If the driver is already in the process of retrieveing AEN's,
220 * we will be returned TW_OSL_EBUSY. In this case,
221 * tw_cli_param_callback or tw_cli_aen_callback will eventually
222 * retrieve the AEN this attention interrupt is for. So, we
223 * don't need to print the failure.
225 if (error != TW_OSL_EBUSY)
226 tw_cl_create_event(ctlr->ctlr_handle, TW_CL_FALSE,
227 TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR,
228 0x1200, 0x1, TW_CL_SEVERITY_ERROR_STRING,
229 "Failed to fetch AEN",
230 "error = %d", error);
237 * Function name: tw_cli_process_cmd_intr
238 * Description: This function gets called if we hit a queue full
239 * condition earlier, and the fw is now ready for
240 * new cmds. Submits any pending requests.
242 * Input: ctlr -- ptr to CL internal ctlr context
247 tw_cli_process_cmd_intr(struct tw_cli_ctlr_context *ctlr)
249 tw_cli_dbg_printf(6, ctlr->ctlr_handle, tw_osl_cur_func(), "entered");
252 * Let the OS Layer submit any requests in its pending queue,
255 tw_osl_ctlr_ready(ctlr->ctlr_handle);
257 /* Start any requests that might be in the pending queue. */
258 tw_cli_submit_pending_queue(ctlr);
261 * If tw_cli_submit_pending_queue was unsuccessful due to a "cmd queue
262 * full" condition, cmd_intr will already have been unmasked by
263 * tw_cli_submit_cmd. We don't need to do it again... simply return.
270 * Function name: tw_cli_process_resp_intr
271 * Description: Looks for cmd completions from fw; queues cmds completed
272 * by fw into complete queue.
274 * Input: ctlr -- ptr to CL internal ctlr context
276 * Return value: 0 -- no ctlr error
277 * non-zero-- ctlr error
280 tw_cli_process_resp_intr(struct tw_cli_ctlr_context *ctlr)
283 struct tw_cli_req_context *req;
285 TW_UINT32 status_reg;
287 tw_cli_dbg_printf(10, ctlr->ctlr_handle, tw_osl_cur_func(), "entered");
289 /* Serialize access to the controller response queue. */
290 tw_osl_get_lock(ctlr->ctlr_handle, ctlr->intr_lock);
293 status_reg = TW_CLI_READ_STATUS_REGISTER(ctlr->ctlr_handle);
294 if ((error = tw_cli_check_ctlr_state(ctlr, status_reg)))
296 if (status_reg & TWA_STATUS_RESPONSE_QUEUE_EMPTY) {
297 tw_cli_dbg_printf(7, ctlr->ctlr_handle,
298 tw_osl_cur_func(), "Response queue empty");
302 /* Response queue is not empty. */
303 resp = TW_CLI_READ_RESPONSE_QUEUE(ctlr->ctlr_handle);
305 req = &(ctlr->req_ctxt_buf[GET_RESP_ID(resp)]);
308 if (req->state != TW_CLI_REQ_STATE_BUSY) {
309 tw_cl_create_event(ctlr->ctlr_handle, TW_CL_FALSE,
310 TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR,
311 0x1201, 0x1, TW_CL_SEVERITY_ERROR_STRING,
312 "Unposted command completed!!",
313 "request = %p, status = %d",
316 tw_cl_print_ctlr_stats(ctlr->ctlr_handle);
317 #endif /* TW_OSL_DEBUG */
318 tw_osl_free_lock(ctlr->ctlr_handle, ctlr->intr_lock);
319 tw_cl_reset_ctlr(ctlr->ctlr_handle);
324 * Remove the request from the busy queue, mark it as complete,
325 * and enqueue it in the complete queue.
327 tw_cli_req_q_remove_item(req, TW_CLI_BUSY_Q);
328 req->state = TW_CLI_REQ_STATE_COMPLETE;
329 tw_cli_req_q_insert_tail(req, TW_CLI_COMPLETE_Q);
333 /* Unmask the response interrupt. */
334 TW_CLI_WRITE_CONTROL_REGISTER(ctlr->ctlr_handle,
335 TWA_CONTROL_UNMASK_RESPONSE_INTERRUPT);
337 tw_osl_free_lock(ctlr->ctlr_handle, ctlr->intr_lock);
339 /* Complete this, and other requests in the complete queue. */
340 tw_cli_process_complete_queue(ctlr);
348 * Function name: tw_cli_submit_pending_queue
349 * Description: Kick starts any requests in the pending queue.
351 * Input: ctlr -- ptr to CL internal ctlr context
353 * Return value: 0 -- all pending requests submitted successfully
354 * non-zero-- otherwise
357 tw_cli_submit_pending_queue(struct tw_cli_ctlr_context *ctlr)
359 struct tw_cli_req_context *req;
360 TW_INT32 error = TW_OSL_ESUCCESS;
362 tw_cli_dbg_printf(3, ctlr->ctlr_handle, tw_osl_cur_func(), "entered");
365 * Pull requests off the pending queue, and submit them.
367 while ((req = tw_cli_req_q_remove_head(ctlr, TW_CLI_PENDING_Q)) !=
369 if ((error = tw_cli_submit_cmd(req))) {
370 if (error == TW_OSL_EBUSY) {
371 tw_cli_dbg_printf(2, ctlr->ctlr_handle,
373 "Requeueing pending request");
374 req->state = TW_CLI_REQ_STATE_PENDING;
376 * Queue the request at the head of the pending
377 * queue, and break away, so we don't try to
378 * submit any more requests.
380 tw_cli_req_q_insert_head(req, TW_CLI_PENDING_Q);
383 tw_cl_create_event(ctlr->ctlr_handle,
385 TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR,
387 TW_CL_SEVERITY_ERROR_STRING,
388 "Could not start request "
390 "request = %p, opcode = 0x%x, "
392 GET_OPCODE(req->cmd_pkt->
393 command.cmd_pkt_9k.res__opcode),
396 * Set the appropriate error and call the CL
397 * internal callback if there's one. If the
398 * request originator is polling for completion,
399 * he should be checking req->error to
400 * determine that the request did not go
401 * through. The request originators are
402 * responsible for the clean-up.
404 req->error_code = error;
405 req->state = TW_CLI_REQ_STATE_COMPLETE;
406 if (req->tw_cli_callback)
407 req->tw_cli_callback(req);
408 error = TW_OSL_ESUCCESS;
418 * Function name: tw_cli_process_complete_queue
419 * Description: Calls the CL internal callback routine, if any, for
420 * each request in the complete queue.
422 * Input: ctlr -- ptr to CL internal ctlr context
427 tw_cli_process_complete_queue(struct tw_cli_ctlr_context *ctlr)
429 struct tw_cli_req_context *req;
431 tw_cli_dbg_printf(10, ctlr->ctlr_handle, tw_osl_cur_func(), "entered");
434 * Pull commands off the completed list, dispatch them appropriately.
436 while ((req = tw_cli_req_q_remove_head(ctlr, TW_CLI_COMPLETE_Q)) !=
438 /* Call the CL internal callback, if there's one. */
439 if (req->tw_cli_callback)
440 req->tw_cli_callback(req);
447 * Function name: tw_cli_complete_io
448 * Description: CL internal callback for SCSI/fw passthru requests.
450 * Input: req -- ptr to CL internal request context
455 tw_cli_complete_io(struct tw_cli_req_context *req)
457 struct tw_cli_ctlr_context *ctlr = req->ctlr;
458 struct tw_cl_req_packet *req_pkt =
459 (struct tw_cl_req_packet *)(req->orig_req);
461 tw_cli_dbg_printf(8, ctlr->ctlr_handle, tw_osl_cur_func(), "entered");
463 req_pkt->status = TW_CL_ERR_REQ_SUCCESS;
464 if (req->error_code) {
465 req_pkt->status = TW_CL_ERR_REQ_UNABLE_TO_SUBMIT_COMMAND;
469 if (req->state != TW_CLI_REQ_STATE_COMPLETE) {
470 tw_cl_create_event(ctlr->ctlr_handle, TW_CL_FALSE,
471 TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR,
472 0x1203, 0x1, TW_CL_SEVERITY_ERROR_STRING,
473 "I/O completion on incomplete command!!",
474 "request = %p, status = %d",
477 tw_cl_print_ctlr_stats(ctlr->ctlr_handle);
478 #endif /* TW_OSL_DEBUG */
479 tw_cl_reset_ctlr(ctlr->ctlr_handle);
480 req_pkt->status = TW_CL_ERR_REQ_BUS_RESET;
484 if (req->flags & TW_CLI_REQ_FLAGS_PASSTHRU) {
485 /* Copy the command packet back into OSL's space. */
486 tw_osl_memcpy(req_pkt->gen_req_pkt.pt_req.cmd_pkt, req->cmd_pkt,
487 sizeof(struct tw_cl_command_packet));
489 tw_cli_scsi_complete(req);
492 req_pkt->tw_osl_callback(req->req_handle);
493 tw_cli_req_q_insert_tail(req, TW_CLI_FREE_Q);
499 * Function name: tw_cli_scsi_complete
500 * Description: Completion routine for SCSI requests.
502 * Input: req -- ptr to CL internal request context
507 tw_cli_scsi_complete(struct tw_cli_req_context *req)
509 struct tw_cl_req_packet *req_pkt =
510 (struct tw_cl_req_packet *)(req->orig_req);
511 struct tw_cl_scsi_req_packet *scsi_req =
512 &(req_pkt->gen_req_pkt.scsi_req);
513 struct tw_cl_command_9k *cmd =
514 &(req->cmd_pkt->command.cmd_pkt_9k);
515 struct tw_cl_command_header *cmd_hdr;
519 tw_cli_dbg_printf(8, req->ctlr->ctlr_handle, tw_osl_cur_func(),
522 scsi_req->scsi_status = cmd->status;
526 tw_cli_dbg_printf(1, req->ctlr->ctlr_handle, tw_osl_cur_func(),
527 "req_id = 0x%x, status = 0x%x",
528 GET_REQ_ID(cmd->lun_l4__req_id), cmd->status);
530 cmd_hdr = &(req->cmd_pkt->cmd_hdr);
531 error = cmd_hdr->status_block.error;
532 if ((error == TWA_ERROR_LOGICAL_UNIT_NOT_SUPPORTED) ||
533 (error == TWA_ERROR_UNIT_OFFLINE)) {
534 if (GET_LUN_L4(cmd->lun_l4__req_id))
535 req_pkt->status |= TW_CL_ERR_REQ_INVALID_LUN;
537 req_pkt->status |= TW_CL_ERR_REQ_INVALID_TARGET;
539 tw_cli_dbg_printf(2, req->ctlr->ctlr_handle,
541 "cmd = %x %x %x %x %x %x %x",
542 GET_OPCODE(cmd->res__opcode),
543 GET_SGL_OFF(cmd->res__opcode),
548 cmd->lun_h4__sgl_entries);
550 cdb = (TW_UINT8 *)(cmd->cdb);
551 tw_cli_dbg_printf(2, req->ctlr->ctlr_handle,
553 "cdb = %x %x %x %x %x %x %x %x "
554 "%x %x %x %x %x %x %x %x",
555 cdb[0], cdb[1], cdb[2], cdb[3],
556 cdb[4], cdb[5], cdb[6], cdb[7],
557 cdb[8], cdb[9], cdb[10], cdb[11],
558 cdb[12], cdb[13], cdb[14], cdb[15]);
561 * Print the error. Firmware doesn't yet support
562 * the 'Mode Sense' cmd. Don't print if the cmd
563 * is 'Mode Sense', and the error is 'Invalid field
566 if (! ((cdb[0] == 0x1A) && (error == 0x10D)))
567 tw_cli_create_ctlr_event(req->ctlr,
568 TW_CL_MESSAGE_SOURCE_CONTROLLER_ERROR,
572 if (scsi_req->sense_data) {
573 tw_osl_memcpy(scsi_req->sense_data, cmd_hdr->sense_data,
574 TWA_SENSE_DATA_LENGTH);
575 scsi_req->sense_len = TWA_SENSE_DATA_LENGTH;
576 req_pkt->status |= TW_CL_ERR_REQ_AUTO_SENSE_VALID;
578 req_pkt->status |= TW_CL_ERR_REQ_SCSI_ERROR;
584 * Function name: tw_cli_param_callback
585 * Description: Callback for get/set_param requests.
587 * Input: req -- ptr to completed request pkt
592 tw_cli_param_callback(struct tw_cli_req_context *req)
594 struct tw_cli_ctlr_context *ctlr = req->ctlr;
595 union tw_cl_command_7k *cmd =
596 &(req->cmd_pkt->command.cmd_pkt_7k);
599 tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(), "entered");
602 * If the request was never submitted to the controller, the function
603 * that sets req->error is responsible for calling tw_cl_create_event.
605 if (! req->error_code)
606 if (cmd->param.status) {
607 tw_cli_create_ctlr_event(ctlr,
608 TW_CL_MESSAGE_SOURCE_CONTROLLER_ERROR,
609 &(req->cmd_pkt->cmd_hdr));
610 tw_cl_create_event(ctlr->ctlr_handle, TW_CL_FALSE,
611 TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR,
612 0x1204, 0x1, TW_CL_SEVERITY_ERROR_STRING,
613 "get/set_param failed",
614 "status = %d", cmd->param.status);
617 ctlr->state &= ~TW_CLI_CTLR_STATE_INTERNAL_REQ_BUSY;
618 tw_cli_req_q_insert_tail(req, TW_CLI_FREE_Q);
620 if ((ctlr->state & TW_CLI_CTLR_STATE_GET_MORE_AENS) &&
621 (!(ctlr->state & TW_CLI_CTLR_STATE_RESET_IN_PROGRESS))) {
622 ctlr->state &= ~TW_CLI_CTLR_STATE_GET_MORE_AENS;
623 tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(),
624 "Fetching more AEN's");
625 if ((error = tw_cli_get_aen(ctlr)))
626 tw_cl_create_event(ctlr->ctlr_handle, TW_CL_FALSE,
627 TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR,
628 0x1205, 0x1, TW_CL_SEVERITY_ERROR_STRING,
629 "Failed to fetch all AEN's from param_callback",
630 "error = %d", error);
637 * Function name: tw_cli_aen_callback
638 * Description: Callback for requests to fetch AEN's.
640 * Input: req -- ptr to completed request pkt
645 tw_cli_aen_callback(struct tw_cli_req_context *req)
647 struct tw_cli_ctlr_context *ctlr = req->ctlr;
648 struct tw_cl_command_header *cmd_hdr;
649 struct tw_cl_command_9k *cmd =
650 &(req->cmd_pkt->command.cmd_pkt_9k);
651 TW_UINT16 aen_code = TWA_AEN_QUEUE_EMPTY;
654 tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(), "entered");
656 tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(),
657 "req_id = 0x%x, req error = %d, status = 0x%x",
658 GET_REQ_ID(cmd->lun_l4__req_id), req->error_code, cmd->status);
661 * If the request was never submitted to the controller, the function
662 * that sets error is responsible for calling tw_cl_create_event.
664 if (!(error = req->error_code))
665 if ((error = cmd->status)) {
666 cmd_hdr = (struct tw_cl_command_header *)
667 (&(req->cmd_pkt->cmd_hdr));
668 tw_cli_create_ctlr_event(ctlr,
669 TW_CL_MESSAGE_SOURCE_CONTROLLER_ERROR,
671 tw_cl_create_event(ctlr->ctlr_handle, TW_CL_FALSE,
672 TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR,
673 0x1206, 0x1, TW_CL_SEVERITY_ERROR_STRING,
674 "Request Sense failed",
675 "opcode = 0x%x, status = %d",
676 GET_OPCODE(cmd->res__opcode), cmd->status);
680 ctlr->state &= ~TW_CLI_CTLR_STATE_INTERNAL_REQ_BUSY;
681 tw_cli_req_q_insert_tail(req, TW_CLI_FREE_Q);
685 tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(),
686 "Request Sense command succeeded");
688 aen_code = tw_cli_manage_aen(ctlr, req);
690 if (aen_code != TWA_AEN_SYNC_TIME_WITH_HOST) {
691 ctlr->state &= ~TW_CLI_CTLR_STATE_INTERNAL_REQ_BUSY;
692 tw_cli_req_q_insert_tail(req, TW_CLI_FREE_Q);
693 if (aen_code != TWA_AEN_QUEUE_EMPTY)
694 if ((error = tw_cli_get_aen(ctlr)))
695 tw_cl_create_event(ctlr->ctlr_handle,
697 TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR,
699 TW_CL_SEVERITY_ERROR_STRING,
700 "Failed to fetch all AEN's",
701 "error = %d", error);
708 * Function name: tw_cli_manage_aen
709 * Description: Handles AEN's.
711 * Input: ctlr -- ptr to CL internal ctlr context
712 * req -- ptr to CL internal request context
717 tw_cli_manage_aen(struct tw_cli_ctlr_context *ctlr,
718 struct tw_cli_req_context *req)
720 struct tw_cl_command_header *cmd_hdr;
726 tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(), "entered");
728 cmd_hdr = (struct tw_cl_command_header *)(req->data);
729 aen_code = cmd_hdr->status_block.error;
732 case TWA_AEN_SYNC_TIME_WITH_HOST:
733 tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(),
734 "Received AEN_SYNC_TIME");
736 * Free the internal req pkt right here, since
737 * tw_cli_set_param will need it.
739 ctlr->state &= ~TW_CLI_CTLR_STATE_INTERNAL_REQ_BUSY;
740 tw_cli_req_q_insert_tail(req, TW_CLI_FREE_Q);
743 * We will use a callback in tw_cli_set_param only when
744 * interrupts are enabled and we can expect our callback
745 * to get called. Setting the TW_CLI_CTLR_STATE_GET_MORE_AENS
746 * flag will make the callback continue to try to retrieve
749 if (ctlr->state & TW_CLI_CTLR_STATE_INTR_ENABLED)
750 ctlr->state |= TW_CLI_CTLR_STATE_GET_MORE_AENS;
751 /* Calculate time (in seconds) since last Sunday 12.00 AM. */
752 local_time = tw_osl_get_local_time();
753 sync_time = (local_time - (3 * 86400)) % 604800;
754 if ((error = tw_cli_set_param(ctlr, TWA_PARAM_TIME_TABLE,
755 TWA_PARAM_TIME_SCHED_TIME, 4,
757 (ctlr->state & TW_CLI_CTLR_STATE_INTR_ENABLED)
758 ? tw_cli_param_callback : TW_CL_NULL)))
759 tw_cl_create_event(ctlr->ctlr_handle, TW_CL_FALSE,
760 TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR,
761 0x1208, 0x1, TW_CL_SEVERITY_ERROR_STRING,
762 "Unable to sync time with ctlr",
763 "error = %d", error);
768 case TWA_AEN_QUEUE_EMPTY:
769 tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(),
775 /* Queue the event. */
777 tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(),
779 tw_cli_create_ctlr_event(ctlr,
780 TW_CL_MESSAGE_SOURCE_CONTROLLER_EVENT,
790 * Function name: tw_cli_enable_interrupts
791 * Description: Enables interrupts on the controller
793 * Input: ctlr -- ptr to CL internal ctlr context
798 tw_cli_enable_interrupts(struct tw_cli_ctlr_context *ctlr)
800 tw_cli_dbg_printf(3, ctlr->ctlr_handle, tw_osl_cur_func(), "entered");
802 ctlr->state |= TW_CLI_CTLR_STATE_INTR_ENABLED;
803 TW_CLI_WRITE_CONTROL_REGISTER(ctlr->ctlr_handle,
804 TWA_CONTROL_CLEAR_ATTENTION_INTERRUPT |
805 TWA_CONTROL_UNMASK_RESPONSE_INTERRUPT |
806 TWA_CONTROL_ENABLE_INTERRUPTS);
812 * Function name: twa_setup
813 * Description: Disables interrupts on the controller
815 * Input: ctlr -- ptr to CL internal ctlr context
820 tw_cli_disable_interrupts(struct tw_cli_ctlr_context *ctlr)
822 tw_cli_dbg_printf(3, ctlr->ctlr_handle, tw_osl_cur_func(), "entered");
824 TW_CLI_WRITE_CONTROL_REGISTER(ctlr->ctlr_handle,
825 TWA_CONTROL_DISABLE_INTERRUPTS);
826 ctlr->state &= ~TW_CLI_CTLR_STATE_INTR_ENABLED;