Deleted Added
full compact
tw_cl_intr.c (169400) tw_cl_intr.c (172496)
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 *
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 $
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
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
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
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
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
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