]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/twa/tw_cl_intr.c
MFV r337027:
[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 /*
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