]> CyberLeo.Net >> Repos - FreeBSD/releng/8.1.git/blob - sys/dev/twa/tw_cl_intr.c
Copy stable/8 to releng/8.1 in preparation for 8.1-RC1.
[FreeBSD/releng/8.1.git] / sys / dev / 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$
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         /* If we get an interrupt while resetting, it is a shared
79            one for another device, so just bail */
80         if (ctlr->state & TW_CLI_CTLR_STATE_RESET_IN_PROGRESS)
81                 goto out;
82
83         /*
84          * Synchronize access between writes to command and control registers
85          * in 64-bit environments, on G66.
86          */
87         if (ctlr->state & TW_CLI_CTLR_STATE_G66_WORKAROUND_NEEDED)
88                 tw_osl_get_lock(ctlr_handle, ctlr->io_lock);
89
90         /* Read the status register to determine the type of interrupt. */
91         status_reg = TW_CLI_READ_STATUS_REGISTER(ctlr_handle);
92         if (tw_cli_check_ctlr_state(ctlr, status_reg))
93                 goto out_unlock;
94
95         /* Clear the interrupt. */
96         if (status_reg & TWA_STATUS_HOST_INTERRUPT) {
97                 tw_cli_dbg_printf(6, ctlr_handle, tw_osl_cur_func(),
98                         "Host interrupt");
99                 TW_CLI_WRITE_CONTROL_REGISTER(ctlr_handle,
100                         TWA_CONTROL_CLEAR_HOST_INTERRUPT);
101                 ctlr->host_intr_pending = 0; /* we don't use this */
102                 rc |= TW_CL_FALSE; /* don't request for a deferred isr call */
103         }
104         if (status_reg & TWA_STATUS_ATTENTION_INTERRUPT) {
105                 tw_cli_dbg_printf(6, ctlr_handle, tw_osl_cur_func(),
106                         "Attention interrupt");
107                 TW_CLI_WRITE_CONTROL_REGISTER(ctlr_handle,
108                         TWA_CONTROL_CLEAR_ATTENTION_INTERRUPT);
109                 ctlr->attn_intr_pending = 1;
110                 rc |= TW_CL_TRUE; /* request for a deferred isr call */
111         }
112         if (status_reg & TWA_STATUS_COMMAND_INTERRUPT) {
113                 tw_cli_dbg_printf(6, ctlr_handle, tw_osl_cur_func(),
114                         "Command interrupt");
115                 TW_CLI_WRITE_CONTROL_REGISTER(ctlr_handle,
116                         TWA_CONTROL_MASK_COMMAND_INTERRUPT);
117                 ctlr->cmd_intr_pending = 1;
118                 rc |= TW_CL_TRUE; /* request for a deferred isr call */
119         }
120         if (status_reg & TWA_STATUS_RESPONSE_INTERRUPT) {
121                 tw_cli_dbg_printf(10, ctlr_handle, tw_osl_cur_func(),
122                         "Response interrupt");
123                 TW_CLI_WRITE_CONTROL_REGISTER(ctlr_handle,
124                         TWA_CONTROL_MASK_RESPONSE_INTERRUPT);
125                 ctlr->resp_intr_pending = 1;
126                 rc |= TW_CL_TRUE; /* request for a deferred isr call */
127         }
128 out_unlock:
129         if (ctlr->state & TW_CLI_CTLR_STATE_G66_WORKAROUND_NEEDED)
130                 tw_osl_free_lock(ctlr_handle, ctlr->io_lock);
131 out:
132         return(rc);
133 }
134
135
136
137 /*
138  * Function name:       tw_cl_deferred_interrupt
139  * Description:         Deferred interrupt handler.  Does most of the processing
140  *                      related to an interrupt.
141  *
142  * Input:               ctlr_handle     -- controller handle
143  * Output:              None
144  * Return value:        None
145  */
146 TW_VOID
147 tw_cl_deferred_interrupt(struct tw_cl_ctlr_handle *ctlr_handle)
148 {
149         struct tw_cli_ctlr_context      *ctlr =
150                 (struct tw_cli_ctlr_context *)(ctlr_handle->cl_ctlr_ctxt);
151
152         tw_cli_dbg_printf(10, ctlr_handle, tw_osl_cur_func(), "entered");
153
154         /* Dispatch based on the kind of interrupt. */
155         if (ctlr->host_intr_pending) {
156                 tw_cli_dbg_printf(6, ctlr_handle, tw_osl_cur_func(),
157                         "Processing Host interrupt");
158                 ctlr->host_intr_pending = 0;
159                 tw_cli_process_host_intr(ctlr);
160         }
161         if (ctlr->attn_intr_pending) {
162                 tw_cli_dbg_printf(6, ctlr_handle, tw_osl_cur_func(),
163                         "Processing Attention interrupt");
164                 ctlr->attn_intr_pending = 0;
165                 tw_cli_process_attn_intr(ctlr);
166         }
167         if (ctlr->cmd_intr_pending) {
168                 tw_cli_dbg_printf(6, ctlr_handle, tw_osl_cur_func(),
169                         "Processing Command interrupt");
170                 ctlr->cmd_intr_pending = 0;
171                 tw_cli_process_cmd_intr(ctlr);
172         }
173         if (ctlr->resp_intr_pending) {
174                 tw_cli_dbg_printf(10, ctlr_handle, tw_osl_cur_func(),
175                         "Processing Response interrupt");
176                 ctlr->resp_intr_pending = 0;
177                 tw_cli_process_resp_intr(ctlr);
178         }
179 }
180
181
182
183 /*
184  * Function name:       tw_cli_process_host_intr
185  * Description:         This function gets called if we triggered an interrupt.
186  *                      We don't use it as of now.
187  *
188  * Input:               ctlr    -- ptr to CL internal ctlr context
189  * Output:              None
190  * Return value:        None
191  */
192 TW_VOID
193 tw_cli_process_host_intr(struct tw_cli_ctlr_context *ctlr)
194 {
195         tw_cli_dbg_printf(6, ctlr->ctlr_handle, tw_osl_cur_func(), "entered");
196 }
197
198
199
200 /*
201  * Function name:       tw_cli_process_attn_intr
202  * Description:         This function gets called if the fw posted an AEN
203  *                      (Asynchronous Event Notification).  It fetches
204  *                      all the AEN's that the fw might have posted.
205  *
206  * Input:               ctlr    -- ptr to CL internal ctlr context
207  * Output:              None
208  * Return value:        None
209  */
210 TW_VOID
211 tw_cli_process_attn_intr(struct tw_cli_ctlr_context *ctlr)
212 {
213         TW_INT32        error;
214
215         tw_cli_dbg_printf(6, ctlr->ctlr_handle, tw_osl_cur_func(), "entered");
216
217         if ((error = tw_cli_get_aen(ctlr))) {
218                 /*
219                  * If the driver is already in the process of retrieveing AEN's,
220                  * we will be returned TW_OSL_EBUSY.  In this case,
221                  * tw_cli_param_callback or tw_cli_aen_callback will eventually
222                  * retrieve the AEN this attention interrupt is for.  So, we
223                  * don't need to print the failure.
224                  */ 
225                 if (error != TW_OSL_EBUSY)
226                         tw_cl_create_event(ctlr->ctlr_handle, TW_CL_FALSE,
227                                 TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR,
228                                 0x1200, 0x1, TW_CL_SEVERITY_ERROR_STRING,
229                                 "Failed to fetch AEN",
230                                 "error = %d", error);
231         }
232 }
233
234
235
236 /*
237  * Function name:       tw_cli_process_cmd_intr
238  * Description:         This function gets called if we hit a queue full
239  *                      condition earlier, and the fw is now ready for
240  *                      new cmds.  Submits any pending requests.
241  *
242  * Input:               ctlr    -- ptr to CL internal ctlr context
243  * Output:              None
244  * Return value:        None
245  */
246 TW_VOID
247 tw_cli_process_cmd_intr(struct tw_cli_ctlr_context *ctlr)
248 {
249         tw_cli_dbg_printf(6, ctlr->ctlr_handle, tw_osl_cur_func(), "entered");
250
251         /*
252          * Let the OS Layer submit any requests in its pending queue,
253          * if it has one.
254          */
255         tw_osl_ctlr_ready(ctlr->ctlr_handle);
256
257         /* Start any requests that might be in the pending queue. */
258         tw_cli_submit_pending_queue(ctlr);
259
260         /*
261          * If tw_cli_submit_pending_queue was unsuccessful due to a "cmd queue
262          * full" condition, cmd_intr will already have been unmasked by
263          * tw_cli_submit_cmd.  We don't need to do it again... simply return.
264          */
265 }
266
267
268
269 /*
270  * Function name:       tw_cli_process_resp_intr
271  * Description:         Looks for cmd completions from fw; queues cmds completed
272  *                      by fw into complete queue.
273  *
274  * Input:               ctlr    -- ptr to CL internal ctlr context
275  * Output:              None
276  * Return value:        0       -- no ctlr error
277  *                      non-zero-- ctlr error
278  */
279 TW_INT32
280 tw_cli_process_resp_intr(struct tw_cli_ctlr_context *ctlr)
281 {
282         TW_UINT32                       resp;
283         struct tw_cli_req_context       *req;
284         TW_INT32                        error;
285         TW_UINT32                       status_reg;
286     
287         tw_cli_dbg_printf(10, ctlr->ctlr_handle, tw_osl_cur_func(), "entered");
288
289         /* Serialize access to the controller response queue. */
290         tw_osl_get_lock(ctlr->ctlr_handle, ctlr->intr_lock);
291
292         for (;;) {
293                 status_reg = TW_CLI_READ_STATUS_REGISTER(ctlr->ctlr_handle);
294                 if ((error = tw_cli_check_ctlr_state(ctlr, status_reg)))
295                         break;
296                 if (status_reg & TWA_STATUS_RESPONSE_QUEUE_EMPTY) {
297                         tw_cli_dbg_printf(7, ctlr->ctlr_handle,
298                                 tw_osl_cur_func(), "Response queue empty");
299                         break;
300                 }
301
302                 /* Response queue is not empty. */
303                 resp = TW_CLI_READ_RESPONSE_QUEUE(ctlr->ctlr_handle);
304                 {
305                         req = &(ctlr->req_ctxt_buf[GET_RESP_ID(resp)]);
306                 }
307
308                 if (req->state != TW_CLI_REQ_STATE_BUSY) {
309                         tw_cl_create_event(ctlr->ctlr_handle, TW_CL_FALSE,
310                                 TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR,
311                                 0x1201, 0x1, TW_CL_SEVERITY_ERROR_STRING,
312                                 "Unposted command completed!!",
313                                 "request = %p, status = %d",
314                                 req, req->state);
315 #ifdef TW_OSL_DEBUG
316                         tw_cl_print_ctlr_stats(ctlr->ctlr_handle);
317 #endif /* TW_OSL_DEBUG */
318                         tw_osl_free_lock(ctlr->ctlr_handle, ctlr->intr_lock);
319                         tw_cl_reset_ctlr(ctlr->ctlr_handle);
320                         return(TW_OSL_EIO);
321                 }
322
323                 /*
324                  * Remove the request from the busy queue, mark it as complete,
325                  * and enqueue it in the complete queue.
326                  */
327                 tw_cli_req_q_remove_item(req, TW_CLI_BUSY_Q);
328                 req->state = TW_CLI_REQ_STATE_COMPLETE;
329                 tw_cli_req_q_insert_tail(req, TW_CLI_COMPLETE_Q);
330
331         }
332
333         /* Unmask the response interrupt. */
334         TW_CLI_WRITE_CONTROL_REGISTER(ctlr->ctlr_handle,
335                 TWA_CONTROL_UNMASK_RESPONSE_INTERRUPT);
336
337         tw_osl_free_lock(ctlr->ctlr_handle, ctlr->intr_lock);
338
339         /* Complete this, and other requests in the complete queue. */
340         tw_cli_process_complete_queue(ctlr);
341         
342         return(error);
343 }
344
345
346
347 /*
348  * Function name:       tw_cli_submit_pending_queue
349  * Description:         Kick starts any requests in the pending queue.
350  *
351  * Input:               ctlr    -- ptr to CL internal ctlr context
352  * Output:              None
353  * Return value:        0       -- all pending requests submitted successfully
354  *                      non-zero-- otherwise
355  */
356 TW_INT32
357 tw_cli_submit_pending_queue(struct tw_cli_ctlr_context *ctlr)
358 {
359         struct tw_cli_req_context       *req;
360         TW_INT32                        error = TW_OSL_ESUCCESS;
361     
362         tw_cli_dbg_printf(3, ctlr->ctlr_handle, tw_osl_cur_func(), "entered");
363         
364         /*
365          * Pull requests off the pending queue, and submit them.
366          */
367         while ((req = tw_cli_req_q_remove_head(ctlr, TW_CLI_PENDING_Q)) !=
368                 TW_CL_NULL) {
369                 if ((error = tw_cli_submit_cmd(req))) {
370                         if (error == TW_OSL_EBUSY) {
371                                 tw_cli_dbg_printf(2, ctlr->ctlr_handle,
372                                         tw_osl_cur_func(),
373                                         "Requeueing pending request");
374                                 req->state = TW_CLI_REQ_STATE_PENDING;
375                                 /*
376                                  * Queue the request at the head of the pending
377                                  * queue, and break away, so we don't try to
378                                  * submit any more requests.
379                                  */
380                                 tw_cli_req_q_insert_head(req, TW_CLI_PENDING_Q);
381                                 break;
382                         } else {
383                                 tw_cl_create_event(ctlr->ctlr_handle,
384                                         TW_CL_FALSE,
385                                         TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR,
386                                         0x1202, 0x1,
387                                         TW_CL_SEVERITY_ERROR_STRING,
388                                         "Could not start request "
389                                         "in pending queue",
390                                         "request = %p, opcode = 0x%x, "
391                                         "error = %d", req,
392                                         GET_OPCODE(req->cmd_pkt->
393                                                 command.cmd_pkt_9k.res__opcode),
394                                         error);
395                                 /*
396                                  * Set the appropriate error and call the CL
397                                  * internal callback if there's one.  If the
398                                  * request originator is polling for completion,
399                                  * he should be checking req->error to
400                                  * determine that the request did not go
401                                  * through.  The request originators are
402                                  * responsible for the clean-up.
403                                  */
404                                 req->error_code = error;
405                                 req->state = TW_CLI_REQ_STATE_COMPLETE;
406                                 if (req->tw_cli_callback)
407                                         req->tw_cli_callback(req);
408                                 error = TW_OSL_ESUCCESS;
409                         }
410                 }
411         }
412         return(error);
413 }
414
415
416
417 /*
418  * Function name:       tw_cli_process_complete_queue
419  * Description:         Calls the CL internal callback routine, if any, for
420  *                      each request in the complete queue.
421  *
422  * Input:               ctlr    -- ptr to CL internal ctlr context
423  * Output:              None
424  * Return value:        None
425  */
426 TW_VOID
427 tw_cli_process_complete_queue(struct tw_cli_ctlr_context *ctlr)
428 {
429         struct tw_cli_req_context       *req;
430     
431         tw_cli_dbg_printf(10, ctlr->ctlr_handle, tw_osl_cur_func(), "entered");
432
433         /*
434          * Pull commands off the completed list, dispatch them appropriately.
435          */
436         while ((req = tw_cli_req_q_remove_head(ctlr, TW_CLI_COMPLETE_Q)) !=
437                 TW_CL_NULL) {
438                 /* Call the CL internal callback, if there's one. */
439                 if (req->tw_cli_callback)
440                         req->tw_cli_callback(req);
441         }
442 }
443
444
445
446 /*
447  * Function name:       tw_cli_complete_io
448  * Description:         CL internal callback for SCSI/fw passthru requests.
449  *
450  * Input:               req     -- ptr to CL internal request context
451  * Output:              None
452  * Return value:        None
453  */
454 TW_VOID
455 tw_cli_complete_io(struct tw_cli_req_context *req)
456 {
457         struct tw_cli_ctlr_context      *ctlr = req->ctlr;
458         struct tw_cl_req_packet         *req_pkt =
459                 (struct tw_cl_req_packet *)(req->orig_req);
460
461         tw_cli_dbg_printf(8, ctlr->ctlr_handle, tw_osl_cur_func(), "entered");
462
463         req_pkt->status = TW_CL_ERR_REQ_SUCCESS;
464         if (req->error_code) {
465                 req_pkt->status = TW_CL_ERR_REQ_UNABLE_TO_SUBMIT_COMMAND;
466                 goto out;
467         }
468
469         if (req->state != TW_CLI_REQ_STATE_COMPLETE) {
470                 tw_cl_create_event(ctlr->ctlr_handle, TW_CL_FALSE,
471                         TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR,
472                         0x1203, 0x1, TW_CL_SEVERITY_ERROR_STRING,
473                         "I/O completion on incomplete command!!",
474                         "request = %p, status = %d",
475                         req, req->state);
476 #ifdef TW_OSL_DEBUG
477                 tw_cl_print_ctlr_stats(ctlr->ctlr_handle);
478 #endif /* TW_OSL_DEBUG */
479                 tw_cl_reset_ctlr(ctlr->ctlr_handle);
480                 req_pkt->status = TW_CL_ERR_REQ_BUS_RESET;
481                 goto out;
482         }
483
484         if (req->flags & TW_CLI_REQ_FLAGS_PASSTHRU) {
485                 /* Copy the command packet back into OSL's space. */
486                 tw_osl_memcpy(req_pkt->gen_req_pkt.pt_req.cmd_pkt, req->cmd_pkt,
487                         sizeof(struct tw_cl_command_packet));
488         } else
489                 tw_cli_scsi_complete(req);
490
491 out:
492         req_pkt->tw_osl_callback(req->req_handle);
493         tw_cli_req_q_insert_tail(req, TW_CLI_FREE_Q);
494 }
495
496
497
498 /*
499  * Function name:       tw_cli_scsi_complete
500  * Description:         Completion routine for SCSI requests.
501  *
502  * Input:               req     -- ptr to CL internal request context
503  * Output:              None
504  * Return value:        None
505  */
506 TW_VOID
507 tw_cli_scsi_complete(struct tw_cli_req_context *req)
508 {
509         struct tw_cl_req_packet         *req_pkt =
510                 (struct tw_cl_req_packet *)(req->orig_req);
511         struct tw_cl_scsi_req_packet    *scsi_req =
512                 &(req_pkt->gen_req_pkt.scsi_req);
513         struct tw_cl_command_9k         *cmd =
514                 &(req->cmd_pkt->command.cmd_pkt_9k);
515         struct tw_cl_command_header     *cmd_hdr;
516         TW_UINT16                       error;
517         TW_UINT8                        *cdb;
518
519         tw_cli_dbg_printf(8, req->ctlr->ctlr_handle, tw_osl_cur_func(),
520                 "entered");
521
522         scsi_req->scsi_status = cmd->status;
523         if (! cmd->status)
524                 return;
525
526         tw_cli_dbg_printf(1, req->ctlr->ctlr_handle, tw_osl_cur_func(),
527                 "req_id = 0x%x, status = 0x%x",
528                 GET_REQ_ID(cmd->lun_l4__req_id), cmd->status);
529
530         cmd_hdr = &(req->cmd_pkt->cmd_hdr);
531         error = cmd_hdr->status_block.error;
532         if ((error == TWA_ERROR_LOGICAL_UNIT_NOT_SUPPORTED) ||
533                         (error == TWA_ERROR_UNIT_OFFLINE)) {
534                 if (GET_LUN_L4(cmd->lun_l4__req_id))
535                         req_pkt->status |= TW_CL_ERR_REQ_INVALID_LUN;
536                 else
537                         req_pkt->status |= TW_CL_ERR_REQ_INVALID_TARGET;
538         } else {
539                 tw_cli_dbg_printf(2, req->ctlr->ctlr_handle,
540                         tw_osl_cur_func(),
541                         "cmd = %x %x %x %x %x %x %x",
542                         GET_OPCODE(cmd->res__opcode),
543                         GET_SGL_OFF(cmd->res__opcode),
544                         cmd->unit,
545                         cmd->lun_l4__req_id,
546                         cmd->status,
547                         cmd->sgl_offset,
548                         cmd->lun_h4__sgl_entries);
549
550                 cdb = (TW_UINT8 *)(cmd->cdb);
551                 tw_cli_dbg_printf(2, req->ctlr->ctlr_handle,
552                         tw_osl_cur_func(),
553                         "cdb = %x %x %x %x %x %x %x %x "
554                         "%x %x %x %x %x %x %x %x",
555                         cdb[0], cdb[1], cdb[2], cdb[3],
556                         cdb[4], cdb[5], cdb[6], cdb[7],
557                         cdb[8], cdb[9], cdb[10], cdb[11],
558                         cdb[12], cdb[13], cdb[14], cdb[15]);
559
560                 /* 
561                  * Print the error. Firmware doesn't yet support
562                  * the 'Mode Sense' cmd.  Don't print if the cmd
563                  * is 'Mode Sense', and the error is 'Invalid field
564                  * in CDB'.
565                  */
566                 if (! ((cdb[0] == 0x1A) && (error == 0x10D)))
567                         tw_cli_create_ctlr_event(req->ctlr,
568                                 TW_CL_MESSAGE_SOURCE_CONTROLLER_ERROR,
569                                 cmd_hdr);
570         }
571
572         if (scsi_req->sense_data) {
573                 tw_osl_memcpy(scsi_req->sense_data, cmd_hdr->sense_data,
574                         TWA_SENSE_DATA_LENGTH);
575                 scsi_req->sense_len = TWA_SENSE_DATA_LENGTH;
576                 req_pkt->status |= TW_CL_ERR_REQ_AUTO_SENSE_VALID;
577         }
578         req_pkt->status |= TW_CL_ERR_REQ_SCSI_ERROR;
579 }
580
581
582
583 /*
584  * Function name:       tw_cli_param_callback
585  * Description:         Callback for get/set_param requests.
586  *
587  * Input:               req     -- ptr to completed request pkt
588  * Output:              None
589  * Return value:        None
590  */
591 TW_VOID
592 tw_cli_param_callback(struct tw_cli_req_context *req)
593 {
594         struct tw_cli_ctlr_context      *ctlr = req->ctlr;
595         union tw_cl_command_7k          *cmd =
596                 &(req->cmd_pkt->command.cmd_pkt_7k);
597         TW_INT32                        error;
598
599         tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(), "entered");
600
601         /*
602          * If the request was never submitted to the controller, the function
603          * that sets req->error is responsible for calling tw_cl_create_event.
604          */
605         if (! req->error_code)
606                 if (cmd->param.status) {
607                         tw_cli_create_ctlr_event(ctlr,
608                                 TW_CL_MESSAGE_SOURCE_CONTROLLER_ERROR,
609                                 &(req->cmd_pkt->cmd_hdr));
610                         tw_cl_create_event(ctlr->ctlr_handle, TW_CL_FALSE,
611                                 TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR,
612                                 0x1204, 0x1, TW_CL_SEVERITY_ERROR_STRING,
613                                 "get/set_param failed",
614                                 "status = %d", cmd->param.status);
615                 }
616
617         ctlr->state &= ~TW_CLI_CTLR_STATE_INTERNAL_REQ_BUSY;
618         tw_cli_req_q_insert_tail(req, TW_CLI_FREE_Q);
619
620         if ((ctlr->state & TW_CLI_CTLR_STATE_GET_MORE_AENS) &&
621                 (!(ctlr->state & TW_CLI_CTLR_STATE_RESET_IN_PROGRESS))) {
622                 ctlr->state &= ~TW_CLI_CTLR_STATE_GET_MORE_AENS;
623                 tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(),
624                         "Fetching more AEN's");
625                 if ((error = tw_cli_get_aen(ctlr)))
626                         tw_cl_create_event(ctlr->ctlr_handle, TW_CL_FALSE,
627                                 TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR,
628                                 0x1205, 0x1, TW_CL_SEVERITY_ERROR_STRING,
629                                 "Failed to fetch all AEN's from param_callback",
630                                 "error = %d", error);
631         }
632 }
633
634
635
636 /*
637  * Function name:       tw_cli_aen_callback
638  * Description:         Callback for requests to fetch AEN's.
639  *
640  * Input:               req     -- ptr to completed request pkt
641  * Output:              None
642  * Return value:        None
643  */
644 TW_VOID
645 tw_cli_aen_callback(struct tw_cli_req_context *req)
646 {
647         struct tw_cli_ctlr_context      *ctlr = req->ctlr;
648         struct tw_cl_command_header     *cmd_hdr;
649         struct tw_cl_command_9k         *cmd =
650                 &(req->cmd_pkt->command.cmd_pkt_9k);
651         TW_UINT16                       aen_code = TWA_AEN_QUEUE_EMPTY;
652         TW_INT32                        error;
653
654         tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(), "entered");
655
656         tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(),
657                 "req_id = 0x%x, req error = %d, status = 0x%x",
658                 GET_REQ_ID(cmd->lun_l4__req_id), req->error_code, cmd->status);
659
660         /*
661          * If the request was never submitted to the controller, the function
662          * that sets error is responsible for calling tw_cl_create_event.
663          */
664         if (!(error = req->error_code))
665                 if ((error = cmd->status)) {
666                         cmd_hdr = (struct tw_cl_command_header *)
667                                 (&(req->cmd_pkt->cmd_hdr));
668                         tw_cli_create_ctlr_event(ctlr,
669                                 TW_CL_MESSAGE_SOURCE_CONTROLLER_ERROR,
670                                 cmd_hdr);
671                         tw_cl_create_event(ctlr->ctlr_handle, TW_CL_FALSE,
672                                 TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR,
673                                 0x1206, 0x1, TW_CL_SEVERITY_ERROR_STRING,
674                                 "Request Sense failed",
675                                 "opcode = 0x%x, status = %d",
676                                 GET_OPCODE(cmd->res__opcode), cmd->status);
677                 }
678
679         if (error) {
680                 ctlr->state &= ~TW_CLI_CTLR_STATE_INTERNAL_REQ_BUSY;
681                 tw_cli_req_q_insert_tail(req, TW_CLI_FREE_Q);
682                 return;
683         }
684
685         tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(),
686                 "Request Sense command succeeded");
687
688         aen_code = tw_cli_manage_aen(ctlr, req);
689
690         if (aen_code != TWA_AEN_SYNC_TIME_WITH_HOST) {
691                 ctlr->state &= ~TW_CLI_CTLR_STATE_INTERNAL_REQ_BUSY;
692                 tw_cli_req_q_insert_tail(req, TW_CLI_FREE_Q);
693                 if (aen_code != TWA_AEN_QUEUE_EMPTY)
694                         if ((error = tw_cli_get_aen(ctlr)))
695                                 tw_cl_create_event(ctlr->ctlr_handle,
696                                         TW_CL_FALSE,
697                                         TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR,
698                                         0x1207, 0x1,
699                                         TW_CL_SEVERITY_ERROR_STRING,
700                                         "Failed to fetch all AEN's",
701                                         "error = %d", error);
702         }
703 }
704
705
706
707 /*
708  * Function name:       tw_cli_manage_aen
709  * Description:         Handles AEN's.
710  *
711  * Input:               ctlr    -- ptr to CL internal ctlr context
712  *                      req     -- ptr to CL internal request context
713  * Output:              None
714  * Return value:        None
715  */
716 TW_UINT16
717 tw_cli_manage_aen(struct tw_cli_ctlr_context *ctlr,
718         struct tw_cli_req_context *req)
719 {
720         struct tw_cl_command_header     *cmd_hdr;
721         TW_UINT16                       aen_code;
722         TW_TIME                         local_time;
723         TW_TIME                         sync_time;
724         TW_UINT32                       error;
725
726         tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(), "entered");
727
728         cmd_hdr = (struct tw_cl_command_header *)(req->data);
729         aen_code = cmd_hdr->status_block.error;
730
731         switch (aen_code) {
732         case TWA_AEN_SYNC_TIME_WITH_HOST:
733                 tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(),
734                         "Received AEN_SYNC_TIME");
735                 /*
736                  * Free the internal req pkt right here, since
737                  * tw_cli_set_param will need it.
738                  */
739                 ctlr->state &= ~TW_CLI_CTLR_STATE_INTERNAL_REQ_BUSY;
740                 tw_cli_req_q_insert_tail(req, TW_CLI_FREE_Q);
741
742                 /*
743                  * We will use a callback in tw_cli_set_param only when
744                  * interrupts are enabled and we can expect our callback
745                  * to get called.  Setting the TW_CLI_CTLR_STATE_GET_MORE_AENS
746                  * flag will make the callback continue to try to retrieve
747                  * more AEN's.
748                  */
749                 if (ctlr->state & TW_CLI_CTLR_STATE_INTR_ENABLED)
750                         ctlr->state |= TW_CLI_CTLR_STATE_GET_MORE_AENS;
751                 /* Calculate time (in seconds) since last Sunday 12.00 AM. */
752                 local_time = tw_osl_get_local_time();
753                 sync_time = (local_time - (3 * 86400)) % 604800;
754                 if ((error = tw_cli_set_param(ctlr, TWA_PARAM_TIME_TABLE,
755                                 TWA_PARAM_TIME_SCHED_TIME, 4,
756                                 &sync_time,
757                                 (ctlr->state & TW_CLI_CTLR_STATE_INTR_ENABLED)
758                                 ? tw_cli_param_callback : TW_CL_NULL)))
759                         tw_cl_create_event(ctlr->ctlr_handle, TW_CL_FALSE,
760                                 TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR,
761                                 0x1208, 0x1, TW_CL_SEVERITY_ERROR_STRING,
762                                 "Unable to sync time with ctlr",
763                                 "error = %d", error);
764
765                 break;
766
767
768         case TWA_AEN_QUEUE_EMPTY:
769                 tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(),
770                         "AEN queue empty");
771                 break;
772
773
774         default:
775                 /* Queue the event. */
776
777                 tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(),
778                         "Queueing AEN");
779                 tw_cli_create_ctlr_event(ctlr,
780                         TW_CL_MESSAGE_SOURCE_CONTROLLER_EVENT,
781                         cmd_hdr);
782                 break;
783         } /* switch */
784         return(aen_code);
785 }
786
787
788
789 /*
790  * Function name:       tw_cli_enable_interrupts
791  * Description:         Enables interrupts on the controller
792  *
793  * Input:               ctlr    -- ptr to CL internal ctlr context
794  * Output:              None
795  * Return value:        None
796  */
797 TW_VOID
798 tw_cli_enable_interrupts(struct tw_cli_ctlr_context *ctlr)
799 {
800         tw_cli_dbg_printf(3, ctlr->ctlr_handle, tw_osl_cur_func(), "entered");
801
802         ctlr->state |= TW_CLI_CTLR_STATE_INTR_ENABLED;
803         TW_CLI_WRITE_CONTROL_REGISTER(ctlr->ctlr_handle,
804                 TWA_CONTROL_CLEAR_ATTENTION_INTERRUPT |
805                 TWA_CONTROL_UNMASK_RESPONSE_INTERRUPT |
806                 TWA_CONTROL_ENABLE_INTERRUPTS);
807 }
808
809
810
811 /*
812  * Function name:       twa_setup
813  * Description:         Disables interrupts on the controller
814  *
815  * Input:               ctlr    -- ptr to CL internal ctlr context
816  * Output:              None
817  * Return value:        None
818  */
819 TW_VOID
820 tw_cli_disable_interrupts(struct tw_cli_ctlr_context *ctlr)
821 {
822         tw_cli_dbg_printf(3, ctlr->ctlr_handle, tw_osl_cur_func(), "entered");
823
824         TW_CLI_WRITE_CONTROL_REGISTER(ctlr->ctlr_handle,
825                 TWA_CONTROL_DISABLE_INTERRUPTS);
826         ctlr->state &= ~TW_CLI_CTLR_STATE_INTR_ENABLED;
827 }
828