8f0cee9dbb9d406f55e24714a0e8db0368425f09
[dragonfly.git] / sys / dev / raid / twa / tw_cl_intr.c
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  *
27  *      $FreeBSD: src/sys/dev/twa/tw_cl_intr.c,v 1.5 2010/06/09 21:40:38 delphij Exp $
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  */
64 TW_INT32
65 tw_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         }
119 out:
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  */
134 TW_VOID
135 tw_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  */
152 TW_VOID
153 tw_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  */
188 TW_VOID
189 tw_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  */
215 TW_INT32
216 tw_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 */
251                         tw_cl_reset_ctlr(ctlr->ctlr_handle);
252                         return(TW_OSL_EIO);
253                 }
254
255                 /*
256                  * Remove the request from the busy queue, mark it as complete,
257                  * and enqueue it in the complete queue.
258                  */
259                 tw_cli_req_q_remove_item(req, TW_CLI_BUSY_Q);
260                 req->state = TW_CLI_REQ_STATE_COMPLETE;
261                 tw_cli_req_q_insert_tail(req, TW_CLI_COMPLETE_Q);
262
263         }
264
265         /* Complete this, and other requests in the complete queue. */
266         tw_cli_process_complete_queue(ctlr);
267
268         return(error);
269 }
270
271
272
273 /*
274  * Function name:       tw_cli_submit_pending_queue
275  * Description:         Kick starts any requests in the pending queue.
276  *
277  * Input:               ctlr    -- ptr to CL internal ctlr context
278  * Output:              None
279  * Return value:        0       -- all pending requests submitted successfully
280  *                      non-zero-- otherwise
281  */
282 TW_INT32
283 tw_cli_submit_pending_queue(struct tw_cli_ctlr_context *ctlr)
284 {
285         struct tw_cli_req_context       *req;
286         TW_INT32                        error = TW_OSL_ESUCCESS;
287
288         tw_cli_dbg_printf(3, ctlr->ctlr_handle, tw_osl_cur_func(), "entered");
289
290         /*
291          * Pull requests off the pending queue, and submit them.
292          */
293         while ((req = tw_cli_req_q_remove_head(ctlr, TW_CLI_PENDING_Q)) !=
294                 TW_CL_NULL) {
295                 if ((error = tw_cli_submit_cmd(req))) {
296                         if (error == TW_OSL_EBUSY) {
297                                 tw_cli_dbg_printf(2, ctlr->ctlr_handle,
298                                         tw_osl_cur_func(),
299                                         "Requeueing pending request");
300                                 req->state = TW_CLI_REQ_STATE_PENDING;
301                                 /*
302                                  * Queue the request at the head of the pending
303                                  * queue, and break away, so we don't try to
304                                  * submit any more requests.
305                                  */
306                                 tw_cli_req_q_insert_head(req, TW_CLI_PENDING_Q);
307                                 break;
308                         } else {
309                                 tw_cl_create_event(ctlr->ctlr_handle,
310                                         TW_CL_FALSE,
311                                         TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR,
312                                         0x1202, 0x1,
313                                         TW_CL_SEVERITY_ERROR_STRING,
314                                         "Could not start request "
315                                         "in pending queue",
316                                         "request = %p, opcode = 0x%x, "
317                                         "error = %d", req,
318                                         GET_OPCODE(req->cmd_pkt->
319                                                 command.cmd_pkt_9k.res__opcode),
320                                         error);
321                                 /*
322                                  * Set the appropriate error and call the CL
323                                  * internal callback if there's one.  If the
324                                  * request originator is polling for completion,
325                                  * he should be checking req->error to
326                                  * determine that the request did not go
327                                  * through.  The request originators are
328                                  * responsible for the clean-up.
329                                  */
330                                 req->error_code = error;
331                                 req->state = TW_CLI_REQ_STATE_COMPLETE;
332                                 if (req->tw_cli_callback)
333                                         req->tw_cli_callback(req);
334                                 error = TW_OSL_ESUCCESS;
335                         }
336                 }
337         }
338         return(error);
339 }
340
341
342
343 /*
344  * Function name:       tw_cli_process_complete_queue
345  * Description:         Calls the CL internal callback routine, if any, for
346  *                      each request in the complete queue.
347  *
348  * Input:               ctlr    -- ptr to CL internal ctlr context
349  * Output:              None
350  * Return value:        None
351  */
352 TW_VOID
353 tw_cli_process_complete_queue(struct tw_cli_ctlr_context *ctlr)
354 {
355         struct tw_cli_req_context       *req;
356
357         tw_cli_dbg_printf(10, ctlr->ctlr_handle, tw_osl_cur_func(), "entered");
358
359         /*
360          * Pull commands off the completed list, dispatch them appropriately.
361          */
362         while ((req = tw_cli_req_q_remove_head(ctlr, TW_CLI_COMPLETE_Q)) !=
363                 TW_CL_NULL) {
364                 /* Call the CL internal callback, if there's one. */
365                 if (req->tw_cli_callback)
366                         req->tw_cli_callback(req);
367         }
368 }
369
370
371
372 /*
373  * Function name:       tw_cli_complete_io
374  * Description:         CL internal callback for SCSI/fw passthru requests.
375  *
376  * Input:               req     -- ptr to CL internal request context
377  * Output:              None
378  * Return value:        None
379  */
380 TW_VOID
381 tw_cli_complete_io(struct tw_cli_req_context *req)
382 {
383         struct tw_cli_ctlr_context      *ctlr = req->ctlr;
384         struct tw_cl_req_packet         *req_pkt =
385                 (struct tw_cl_req_packet *)(req->orig_req);
386
387         tw_cli_dbg_printf(8, ctlr->ctlr_handle, tw_osl_cur_func(), "entered");
388
389         req_pkt->status = TW_CL_ERR_REQ_SUCCESS;
390         if (req->error_code) {
391                 req_pkt->status = TW_CL_ERR_REQ_UNABLE_TO_SUBMIT_COMMAND;
392                 goto out;
393         }
394
395         if (req->state != TW_CLI_REQ_STATE_COMPLETE) {
396                 tw_cl_create_event(ctlr->ctlr_handle, TW_CL_FALSE,
397                         TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR,
398                         0x1203, 0x1, TW_CL_SEVERITY_ERROR_STRING,
399                         "I/O completion on incomplete command!!",
400                         "request = %p, status = %d",
401                         req, req->state);
402 #ifdef TW_OSL_DEBUG
403                 tw_cl_print_ctlr_stats(ctlr->ctlr_handle);
404 #endif /* TW_OSL_DEBUG */
405                 tw_cl_reset_ctlr(ctlr->ctlr_handle);
406                 req_pkt->status = TW_CL_ERR_REQ_BUS_RESET;
407                 goto out;
408         }
409
410         if (req->flags & TW_CLI_REQ_FLAGS_PASSTHRU) {
411                 /* Copy the command packet back into OSL's space. */
412                 tw_osl_memcpy(req_pkt->gen_req_pkt.pt_req.cmd_pkt, req->cmd_pkt,
413                         sizeof(struct tw_cl_command_packet));
414         } else
415                 tw_cli_scsi_complete(req);
416
417 out:
418         req_pkt->tw_osl_callback(req->req_handle);
419         tw_cli_req_q_insert_tail(req, TW_CLI_FREE_Q);
420 }
421
422
423
424 /*
425  * Function name:       tw_cli_scsi_complete
426  * Description:         Completion routine for SCSI requests.
427  *
428  * Input:               req     -- ptr to CL internal request context
429  * Output:              None
430  * Return value:        None
431  */
432 TW_VOID
433 tw_cli_scsi_complete(struct tw_cli_req_context *req)
434 {
435         struct tw_cl_req_packet         *req_pkt =
436                 (struct tw_cl_req_packet *)(req->orig_req);
437         struct tw_cl_scsi_req_packet    *scsi_req =
438                 &(req_pkt->gen_req_pkt.scsi_req);
439         struct tw_cl_command_9k         *cmd =
440                 &(req->cmd_pkt->command.cmd_pkt_9k);
441         struct tw_cl_command_header     *cmd_hdr;
442         TW_UINT16                       error;
443         TW_UINT8                        *cdb;
444
445         tw_cli_dbg_printf(8, req->ctlr->ctlr_handle, tw_osl_cur_func(),
446                 "entered");
447
448         scsi_req->scsi_status = cmd->status;
449         if (! cmd->status)
450                 return;
451
452         tw_cli_dbg_printf(1, req->ctlr->ctlr_handle, tw_osl_cur_func(),
453                 "req_id = 0x%x, status = 0x%x",
454                 GET_REQ_ID(cmd->lun_l4__req_id), cmd->status);
455
456         cmd_hdr = &(req->cmd_pkt->cmd_hdr);
457         error = cmd_hdr->status_block.error;
458         if ((error == TWA_ERROR_LOGICAL_UNIT_NOT_SUPPORTED) ||
459                         (error == TWA_ERROR_UNIT_OFFLINE)) {
460                 if (GET_LUN_L4(cmd->lun_l4__req_id))
461                         req_pkt->status |= TW_CL_ERR_REQ_INVALID_LUN;
462                 else
463                         req_pkt->status |= TW_CL_ERR_REQ_INVALID_TARGET;
464         } else {
465                 tw_cli_dbg_printf(2, req->ctlr->ctlr_handle,
466                         tw_osl_cur_func(),
467                         "cmd = %x %x %x %x %x %x %x",
468                         GET_OPCODE(cmd->res__opcode),
469                         GET_SGL_OFF(cmd->res__opcode),
470                         cmd->unit,
471                         cmd->lun_l4__req_id,
472                         cmd->status,
473                         cmd->sgl_offset,
474                         cmd->lun_h4__sgl_entries);
475
476                 cdb = (TW_UINT8 *)(cmd->cdb);
477                 tw_cli_dbg_printf(2, req->ctlr->ctlr_handle,
478                         tw_osl_cur_func(),
479                         "cdb = %x %x %x %x %x %x %x %x "
480                         "%x %x %x %x %x %x %x %x",
481                         cdb[0], cdb[1], cdb[2], cdb[3],
482                         cdb[4], cdb[5], cdb[6], cdb[7],
483                         cdb[8], cdb[9], cdb[10], cdb[11],
484                         cdb[12], cdb[13], cdb[14], cdb[15]);
485
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         }
497
498         if (scsi_req->sense_data) {
499                 tw_osl_memcpy(scsi_req->sense_data, cmd_hdr->sense_data,
500                         TWA_SENSE_DATA_LENGTH);
501                 scsi_req->sense_len = TWA_SENSE_DATA_LENGTH;
502                 req_pkt->status |= TW_CL_ERR_REQ_AUTO_SENSE_VALID;
503         }
504         req_pkt->status |= TW_CL_ERR_REQ_SCSI_ERROR;
505 }
506
507
508
509 /*
510  * Function name:       tw_cli_param_callback
511  * Description:         Callback for get/set_param requests.
512  *
513  * Input:               req     -- ptr to completed request pkt
514  * Output:              None
515  * Return value:        None
516  */
517 TW_VOID
518 tw_cli_param_callback(struct tw_cli_req_context *req)
519 {
520         struct tw_cli_ctlr_context      *ctlr = req->ctlr;
521         union tw_cl_command_7k          *cmd =
522                 &(req->cmd_pkt->command.cmd_pkt_7k);
523         TW_INT32                        error;
524
525         tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(), "entered");
526
527         /*
528          * If the request was never submitted to the controller, the function
529          * that sets req->error is responsible for calling tw_cl_create_event.
530          */
531         if (! req->error_code)
532                 if (cmd->param.status) {
533                         tw_cli_create_ctlr_event(ctlr,
534                                 TW_CL_MESSAGE_SOURCE_CONTROLLER_ERROR,
535                                 &(req->cmd_pkt->cmd_hdr));
536                         tw_cl_create_event(ctlr->ctlr_handle, TW_CL_FALSE,
537                                 TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR,
538                                 0x1204, 0x1, TW_CL_SEVERITY_ERROR_STRING,
539                                 "get/set_param failed",
540                                 "status = %d", cmd->param.status);
541                 }
542
543         ctlr->internal_req_busy = TW_CL_FALSE;
544         tw_cli_req_q_insert_tail(req, TW_CLI_FREE_Q);
545
546         if ((ctlr->get_more_aens) && (!(ctlr->reset_in_progress))) {
547                 ctlr->get_more_aens = TW_CL_FALSE;
548                 tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(),
549                         "Fetching more AEN's");
550                 if ((error = tw_cli_get_aen(ctlr)))
551                         tw_cl_create_event(ctlr->ctlr_handle, TW_CL_FALSE,
552                                 TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR,
553                                 0x1205, 0x1, TW_CL_SEVERITY_ERROR_STRING,
554                                 "Failed to fetch all AEN's from param_callback",
555                                 "error = %d", error);
556         }
557 }
558
559
560
561 /*
562  * Function name:       tw_cli_aen_callback
563  * Description:         Callback for requests to fetch AEN's.
564  *
565  * Input:               req     -- ptr to completed request pkt
566  * Output:              None
567  * Return value:        None
568  */
569 TW_VOID
570 tw_cli_aen_callback(struct tw_cli_req_context *req)
571 {
572         struct tw_cli_ctlr_context      *ctlr = req->ctlr;
573         struct tw_cl_command_header     *cmd_hdr;
574         struct tw_cl_command_9k         *cmd =
575                 &(req->cmd_pkt->command.cmd_pkt_9k);
576         TW_UINT16                       aen_code = TWA_AEN_QUEUE_EMPTY;
577         TW_INT32                        error;
578
579         tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(), "entered");
580
581         tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(),
582                 "req_id = 0x%x, req error = %d, status = 0x%x",
583                 GET_REQ_ID(cmd->lun_l4__req_id), req->error_code, cmd->status);
584
585         /*
586          * If the request was never submitted to the controller, the function
587          * that sets error is responsible for calling tw_cl_create_event.
588          */
589         if (!(error = req->error_code))
590                 if ((error = cmd->status)) {
591                         cmd_hdr = (struct tw_cl_command_header *)
592                                 (&(req->cmd_pkt->cmd_hdr));
593                         tw_cli_create_ctlr_event(ctlr,
594                                 TW_CL_MESSAGE_SOURCE_CONTROLLER_ERROR,
595                                 cmd_hdr);
596                         tw_cl_create_event(ctlr->ctlr_handle, TW_CL_FALSE,
597                                 TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR,
598                                 0x1206, 0x1, TW_CL_SEVERITY_ERROR_STRING,
599                                 "Request Sense failed",
600                                 "opcode = 0x%x, status = %d",
601                                 GET_OPCODE(cmd->res__opcode), cmd->status);
602                 }
603
604         if (error) {
605                 ctlr->internal_req_busy = TW_CL_FALSE;
606                 tw_cli_req_q_insert_tail(req, TW_CLI_FREE_Q);
607                 return;
608         }
609
610         tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(),
611                 "Request Sense command succeeded");
612
613         aen_code = tw_cli_manage_aen(ctlr, req);
614
615         if (aen_code != TWA_AEN_SYNC_TIME_WITH_HOST) {
616                 ctlr->internal_req_busy = TW_CL_FALSE;
617                 tw_cli_req_q_insert_tail(req, TW_CLI_FREE_Q);
618                 if (aen_code != TWA_AEN_QUEUE_EMPTY)
619                         if ((error = tw_cli_get_aen(ctlr)))
620                                 tw_cl_create_event(ctlr->ctlr_handle,
621                                         TW_CL_FALSE,
622                                         TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR,
623                                         0x1207, 0x1,
624                                         TW_CL_SEVERITY_ERROR_STRING,
625                                         "Failed to fetch all AEN's",
626                                         "error = %d", error);
627         }
628 }
629
630
631
632 /*
633  * Function name:       tw_cli_manage_aen
634  * Description:         Handles AEN's.
635  *
636  * Input:               ctlr    -- ptr to CL internal ctlr context
637  *                      req     -- ptr to CL internal request context
638  * Output:              None
639  * Return value:        None
640  */
641 TW_UINT16
642 tw_cli_manage_aen(struct tw_cli_ctlr_context *ctlr,
643         struct tw_cli_req_context *req)
644 {
645         struct tw_cl_command_header     *cmd_hdr;
646         TW_UINT16                       aen_code;
647         TW_TIME                         local_time;
648         TW_TIME                         sync_time;
649         TW_UINT32                       error;
650
651         tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(), "entered");
652
653         cmd_hdr = (struct tw_cl_command_header *)(req->data);
654         aen_code = cmd_hdr->status_block.error;
655
656         switch (aen_code) {
657         case TWA_AEN_SYNC_TIME_WITH_HOST:
658                 tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(),
659                         "Received AEN_SYNC_TIME");
660                 /*
661                  * Free the internal req pkt right here, since
662                  * tw_cli_set_param will need it.
663                  */
664                 ctlr->internal_req_busy = TW_CL_FALSE;
665                 tw_cli_req_q_insert_tail(req, TW_CLI_FREE_Q);
666
667                 /*
668                  * We will use a callback in tw_cli_set_param only when
669                  * interrupts are enabled and we can expect our callback
670                  * to get called.  Setting the get_more_aens
671                  * flag will make the callback continue to try to retrieve
672                  * more AEN's.
673                  */
674                 if (ctlr->interrupts_enabled)
675                         ctlr->get_more_aens = TW_CL_TRUE;
676                 /* Calculate time (in seconds) since last Sunday 12.00 AM. */
677                 local_time = tw_osl_get_local_time();
678                 sync_time = (local_time - (3 * 86400)) % 604800;
679                 if ((error = tw_cli_set_param(ctlr, TWA_PARAM_TIME_TABLE,
680                                 TWA_PARAM_TIME_SCHED_TIME, 4,
681                                 &sync_time,
682                                 (ctlr->interrupts_enabled)
683                                 ? tw_cli_param_callback : TW_CL_NULL)))
684                         tw_cl_create_event(ctlr->ctlr_handle, TW_CL_FALSE,
685                                 TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR,
686                                 0x1208, 0x1, TW_CL_SEVERITY_ERROR_STRING,
687                                 "Unable to sync time with ctlr",
688                                 "error = %d", error);
689
690                 break;
691
692
693         case TWA_AEN_QUEUE_EMPTY:
694                 tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(),
695                         "AEN queue empty");
696                 break;
697
698
699         default:
700                 /* Queue the event. */
701
702                 tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(),
703                         "Queueing AEN");
704                 tw_cli_create_ctlr_event(ctlr,
705                         TW_CL_MESSAGE_SOURCE_CONTROLLER_EVENT,
706                         cmd_hdr);
707                 break;
708         } /* switch */
709         return(aen_code);
710 }
711
712
713
714 /*
715  * Function name:       tw_cli_enable_interrupts
716  * Description:         Enables interrupts on the controller
717  *
718  * Input:               ctlr    -- ptr to CL internal ctlr context
719  * Output:              None
720  * Return value:        None
721  */
722 TW_VOID
723 tw_cli_enable_interrupts(struct tw_cli_ctlr_context *ctlr)
724 {
725         tw_cli_dbg_printf(3, ctlr->ctlr_handle, tw_osl_cur_func(), "entered");
726
727         ctlr->interrupts_enabled = TW_CL_TRUE;
728         TW_CLI_WRITE_CONTROL_REGISTER(ctlr->ctlr_handle,
729                 TWA_CONTROL_CLEAR_ATTENTION_INTERRUPT |
730                 TWA_CONTROL_UNMASK_RESPONSE_INTERRUPT |
731                 TWA_CONTROL_ENABLE_INTERRUPTS);
732 }
733
734
735
736 /*
737  * Function name:       twa_setup
738  * Description:         Disables interrupts on the controller
739  *
740  * Input:               ctlr    -- ptr to CL internal ctlr context
741  * Output:              None
742  * Return value:        None
743  */
744 TW_VOID
745 tw_cli_disable_interrupts(struct tw_cli_ctlr_context *ctlr)
746 {
747         tw_cli_dbg_printf(3, ctlr->ctlr_handle, tw_osl_cur_func(), "entered");
748
749         TW_CLI_WRITE_CONTROL_REGISTER(ctlr->ctlr_handle,
750                 TWA_CONTROL_DISABLE_INTERRUPTS);
751         ctlr->interrupts_enabled = TW_CL_FALSE;
752 }