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