]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/twa/tw_cl_intr.c
Import tzdata 2020c
[FreeBSD/FreeBSD.git] / sys / dev / twa / tw_cl_intr.c
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 }