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