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 172496 2007-10-09 17:43:57Z scottl $
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 */
64TW_INT32
65tw_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 }
128out_unlock:
129 if (ctlr->state & TW_CLI_CTLR_STATE_G66_WORKAROUND_NEEDED)
130 tw_osl_free_lock(ctlr_handle, ctlr->io_lock);
131out:
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 */
146TW_VOID
147tw_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 */
192TW_VOID
193tw_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 */
210TW_VOID
211tw_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 */
246TW_VOID
247tw_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 */
279TW_INT32
280tw_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 */
356TW_INT32
357tw_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 */
426TW_VOID
427tw_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 */
454TW_VOID
455tw_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
491out:
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 */
506TW_VOID
507tw_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 */
591TW_VOID
592tw_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 */
644TW_VOID
645tw_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 */
716TW_UINT16
717tw_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 */
797TW_VOID
798tw_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 */
819TW_VOID
820tw_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
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 172496 2007-10-09 17:43:57Z scottl $
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 */
64TW_INT32
65tw_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 }
128out_unlock:
129 if (ctlr->state & TW_CLI_CTLR_STATE_G66_WORKAROUND_NEEDED)
130 tw_osl_free_lock(ctlr_handle, ctlr->io_lock);
131out:
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 */
146TW_VOID
147tw_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 */
192TW_VOID
193tw_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 */
210TW_VOID
211tw_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 */
246TW_VOID
247tw_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 */
279TW_INT32
280tw_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 */
356TW_INT32
357tw_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 */
426TW_VOID
427tw_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 */
454TW_VOID
455tw_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
491out:
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 */
506TW_VOID
507tw_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 */
591TW_VOID
592tw_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 */
644TW_VOID
645tw_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 */
716TW_UINT16
717tw_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 */
797TW_VOID
798tw_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 */
819TW_VOID
820tw_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