1 /*
2 * Copyright (c) 2004-05 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: releng/6.1/sys/dev/twa/tw_cl_misc.c 153207 2005-12-07 18:18:06Z vkashyap $
28 */
29
30 /*
31 * AMCC'S 3ware driver for 9000 series storage controllers.
32 *
33 * Author: Vinod Kashyap
34 */
35
36
37 /*
38 * Common Layer miscellaneous functions.
39 */
40
41
42 #include "tw_osl_share.h"
43 #include "tw_cl_share.h"
44 #include "tw_cl_fwif.h"
45 #include "tw_cl_ioctl.h"
46 #include "tw_cl.h"
47 #include "tw_cl_externs.h"
48 #include "tw_osl_ioctl.h"
49
50
51
52 /* AEN severity table. */
53 TW_INT8 *tw_cli_severity_string_table[] = {
54 "None",
55 TW_CL_SEVERITY_ERROR_STRING,
56 TW_CL_SEVERITY_WARNING_STRING,
57 TW_CL_SEVERITY_INFO_STRING,
58 TW_CL_SEVERITY_DEBUG_STRING,
59 ""
60 };
61
62
63
64 /*
65 * Function name: tw_cli_drain_complete_queue
66 * Description: This function gets called during a controller reset.
67 * It errors back to the OS Layer, all those requests that
68 * are in the complete queue, at the time of the reset.
69 * Any CL internal requests will be simply freed.
70 *
71 * Input: ctlr -- ptr to CL internal ctlr context
72 * Output: None
73 * Return value: None
74 */
75 TW_VOID
76 tw_cli_drain_complete_queue(struct tw_cli_ctlr_context *ctlr)
77 {
78 struct tw_cli_req_context *req;
79 struct tw_cl_req_packet *req_pkt;
80
81 tw_cli_dbg_printf(3, ctlr->ctlr_handle, tw_osl_cur_func(), "entered");
82
83 /* Walk the busy queue. */
84 while ((req = tw_cli_req_q_remove_head(ctlr, TW_CLI_COMPLETE_Q))) {
85 if (req->flags & TW_CLI_REQ_FLAGS_INTERNAL) {
86 /*
87 * It's an internal request. Set the appropriate
88 * error and call the CL internal callback if there's
89 * one. If the request originator is polling for
90 * completion, he should be checking req->error to
91 * determine that the request did not go through.
92 * The request originators are responsible for the
93 * clean-up.
94 */
95 req->error_code = TW_CL_ERR_REQ_BUS_RESET;
96 if (req->tw_cli_callback)
97 req->tw_cli_callback(req);
98 } else {
99 if ((req_pkt = req->orig_req)) {
100 /* It's a SCSI request. Complete it. */
101 tw_cli_dbg_printf(2, ctlr->ctlr_handle,
102 tw_osl_cur_func(),
103 "Completing complete request %p "
104 "on reset",
105 req);
106 req_pkt->status = TW_CL_ERR_REQ_BUS_RESET;
107 req_pkt->tw_osl_callback(req->req_handle);
108 }
109 tw_cli_req_q_insert_tail(req, TW_CLI_FREE_Q);
110 }
111 }
112 }
113
114
115
116 /*
117 * Function name: tw_cli_drain_busy_queue
118 * Description: This function gets called during a controller reset.
119 * It errors back to the OS Layer, all those requests that
120 * were pending with the firmware, at the time of the
121 * reset.
122 *
123 * Input: ctlr -- ptr to CL internal ctlr context
124 * Output: None
125 * Return value: None
126 */
127 TW_VOID
128 tw_cli_drain_busy_queue(struct tw_cli_ctlr_context *ctlr)
129 {
130 struct tw_cli_req_context *req;
131 struct tw_cl_req_packet *req_pkt;
132
133 tw_cli_dbg_printf(3, ctlr->ctlr_handle, tw_osl_cur_func(), "entered");
134
135 /* Walk the busy queue. */
136 while ((req = tw_cli_req_q_remove_head(ctlr, TW_CLI_BUSY_Q))) {
137 if (req->flags & TW_CLI_REQ_FLAGS_INTERNAL) {
138 /*
139 * It's an internal request. Set the appropriate
140 * error and call the CL internal callback if there's
141 * one. If the request originator is polling for
142 * completion, he should be checking req->error to
143 * determine that the request did not go through.
144 * The request originators are responsible for the
145 * clean-up.
146 */
147 req->error_code = TW_CL_ERR_REQ_BUS_RESET;
148 if (req->tw_cli_callback)
149 req->tw_cli_callback(req);
150 } else {
151 if ((req_pkt = req->orig_req)) {
152 /* It's a SCSI request. Complete it. */
153 tw_cli_dbg_printf(2, ctlr->ctlr_handle,
154 tw_osl_cur_func(),
155 "Completing busy request %p on reset",
156 req);
157 req_pkt->status = TW_CL_ERR_REQ_BUS_RESET;
158 req_pkt->tw_osl_callback(req->req_handle);
159 }
160 tw_cli_req_q_insert_tail(req, TW_CLI_FREE_Q);
161 }
162 }
163 }
164
165
166
167 /*
168 * Function name: tw_cli_drain_pending_queue
169 * Description: This function gets called during a controller reset.
170 * It errors back to the OS Layer, all those requests that
171 * were in the pending queue, at the time of the reset.
172 *
173 * Input: ctlr -- ptr to CL internal ctlr context
174 * Output: None
175 * Return value: None
176 */
177
178 TW_VOID
179 tw_cli_drain_pending_queue(struct tw_cli_ctlr_context *ctlr)
180 {
181 struct tw_cli_req_context *req;
182 struct tw_cl_req_packet *req_pkt;
183
184 tw_cli_dbg_printf(3, ctlr->ctlr_handle, tw_osl_cur_func(), "entered");
185
186 /*
187 * Pull requests off the pending queue, and complete them.
188 */
189 while ((req = tw_cli_req_q_remove_head(ctlr, TW_CLI_PENDING_Q))) {
190 if (req->flags & TW_CLI_REQ_FLAGS_INTERNAL) {
191 /*
192 * It's an internal request. Set the appropriate
193 * error and call the CL internal callback if there's
194 * one. If the request originator is polling for
195 * completion, he should be checking req->error to
196 * determine that the request did not go through.
197 * The request originators are responsible for the
198 * clean-up.
199 */
200 req->error_code = TW_CL_ERR_REQ_BUS_RESET;
201 if (req->tw_cli_callback)
202 req->tw_cli_callback(req);
203 } else {
204 if ((req_pkt = req->orig_req)) {
205 /* It's an external request. Complete it. */
206 tw_cli_dbg_printf(2, ctlr->ctlr_handle,
207 tw_osl_cur_func(),
208 "Completing pending request %p "
209 "on reset", req);
210 req_pkt->status = TW_CL_ERR_REQ_BUS_RESET;
211 req_pkt->tw_osl_callback(req->req_handle);
212 }
213 tw_cli_req_q_insert_tail(req, TW_CLI_FREE_Q);
214 }
215 }
216 }
217
218
219
220 /*
221 * Function name: tw_cli_drain_response_queue
222 * Description: Drain the controller response queue.
223 *
224 * Input: ctlr -- ptr to per ctlr structure
225 * Output: None
226 * Return value: 0 -- success
227 * non-zero-- failure
228 */
229 TW_INT32
230 tw_cli_drain_response_queue(struct tw_cli_ctlr_context *ctlr)
231 {
232 TW_UINT32 resp;
233 TW_UINT32 status_reg;
234
235 tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(), "entered");
236
237 for (;;) {
238 status_reg = TW_CLI_READ_STATUS_REGISTER(ctlr->ctlr_handle);
239
240 if (tw_cli_check_ctlr_state(ctlr, status_reg))
241 return(TW_OSL_EGENFAILURE);
242
243 if (status_reg & TWA_STATUS_RESPONSE_QUEUE_EMPTY)
244 return(TW_OSL_ESUCCESS); /* no more response queue entries */
245
246 resp = TW_CLI_READ_RESPONSE_QUEUE(ctlr->ctlr_handle);
247 }
248 }
249
250
251
252 /*
253 * Function name: tw_cli_find_response
254 * Description: Find a particular response in the ctlr response queue.
255 *
256 * Input: ctlr -- ptr to per ctlr structure
257 * req_id -- request id of the response to look for
258 * Output: None
259 * Return value: 0 -- success
260 * non-zero-- failure
261 */
262 TW_INT32
263 tw_cli_find_response(struct tw_cli_ctlr_context *ctlr, TW_INT32 req_id)
264 {
265 TW_UINT32 resp;
266 TW_INT32 resp_id;
267 TW_UINT32 status_reg;
268
269 tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(), "entered");
270
271 for (;;) {
272 status_reg = TW_CLI_READ_STATUS_REGISTER(ctlr->ctlr_handle);
273
274 if (tw_cli_check_ctlr_state(ctlr, status_reg))
275 return(TW_OSL_EGENFAILURE);
276
277 if (status_reg & TWA_STATUS_RESPONSE_QUEUE_EMPTY)
278 return(TW_OSL_ENOTTY); /* no more response queue entries */
279
280 if (ctlr->device_id == TW_CL_DEVICE_ID_9K) {
281 resp = TW_CLI_READ_RESPONSE_QUEUE(ctlr->ctlr_handle);
282 resp_id = GET_RESP_ID(resp);
283 } else {
284 resp = TW_CLI_READ_LARGE_RESPONSE_QUEUE(
285 ctlr->ctlr_handle);
286 resp_id = GET_LARGE_RESP_ID(resp);
287 }
288 if (resp_id == req_id)
289 return(TW_OSL_ESUCCESS); /* found the req_id */
290 }
291 }
292
293
294
295 /*
296 * Function name: tw_cli_drain_aen_queue
297 * Description: Fetches all un-retrieved AEN's posted by fw.
298 *
299 * Input: ctlr -- ptr to CL internal ctlr context
300 * Output: None
301 * Return value: 0 -- success
302 * non-zero-- failure
303 */
304 TW_INT32
305 tw_cli_drain_aen_queue(struct tw_cli_ctlr_context *ctlr)
306 {
307 struct tw_cli_req_context *req;
308 struct tw_cl_command_header *cmd_hdr;
309 TW_TIME end_time;
310 TW_UINT16 aen_code;
311 TW_INT32 error;
312
313 tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(), "entered");
314
315 for (;;) {
316 if ((req = tw_cli_get_request(ctlr
317 #ifdef TW_OSL_NON_DMA_MEM_ALLOC_PER_REQUEST
318 , TW_CL_NULL
319 #endif /* TW_OSL_NON_DMA_MEM_ALLOC_PER_REQUEST */
320 )) == TW_CL_NULL) {
321 error = TW_OSL_EBUSY;
322 break;
323 }
324
325 #ifdef TW_OSL_DMA_MEM_ALLOC_PER_REQUEST
326
327 req->cmd_pkt = ctlr->cmd_pkt_buf;
328 req->cmd_pkt_phys = ctlr->cmd_pkt_phys;
329 tw_osl_memzero(req->cmd_pkt,
330 sizeof(struct tw_cl_command_header) +
331 28 /* max bytes before sglist */);
332
333 #endif /* TW_OSL_DMA_MEM_ALLOC_PER_REQUEST */
334
335 req->flags |= TW_CLI_REQ_FLAGS_INTERNAL;
336 req->tw_cli_callback = TW_CL_NULL;
337 if ((error = tw_cli_send_scsi_cmd(req,
338 0x03 /* REQUEST_SENSE */))) {
339 tw_cli_dbg_printf(1, ctlr->ctlr_handle,
340 tw_osl_cur_func(),
341 "Cannot send command to fetch aen");
342 break;
343 }
344
345 end_time = tw_osl_get_local_time() +
346 TW_CLI_REQUEST_TIMEOUT_PERIOD;
347 do {
348 if ((error = req->error_code))
349 /*
350 * This will take care of completion due to
351 * a reset, or a failure in
352 * tw_cli_submit_pending_queue.
353 */
354 goto out;
355
356 tw_cli_process_resp_intr(req->ctlr);
357
358 if ((req->state != TW_CLI_REQ_STATE_BUSY) &&
359 (req->state != TW_CLI_REQ_STATE_PENDING))
360 break;
361 } while (tw_osl_get_local_time() <= end_time);
362
363 if (req->state != TW_CLI_REQ_STATE_COMPLETE) {
364 error = TW_OSL_ETIMEDOUT;
365 break;
366 }
367
368 if ((error = req->cmd_pkt->command.cmd_pkt_9k.status)) {
369 cmd_hdr = &req->cmd_pkt->cmd_hdr;
370 tw_cli_create_ctlr_event(ctlr,
371 TW_CL_MESSAGE_SOURCE_CONTROLLER_ERROR,
372 cmd_hdr);
373 break;
374 }
375
376 aen_code = tw_cli_manage_aen(ctlr, req);
377 if (aen_code == TWA_AEN_QUEUE_EMPTY)
378 break;
379 if (aen_code == TWA_AEN_SYNC_TIME_WITH_HOST)
380 continue;
381
382 ctlr->state &= ~TW_CLI_CTLR_STATE_INTERNAL_REQ_BUSY;
383 tw_cli_req_q_insert_tail(req, TW_CLI_FREE_Q);
384 }
385
386 out:
387 if (req) {
388 if (req->data)
389 ctlr->state &= ~TW_CLI_CTLR_STATE_INTERNAL_REQ_BUSY;
390 tw_cli_req_q_insert_tail(req, TW_CLI_FREE_Q);
391 }
392 return(error);
393 }
394
395
396
397 /*
398 * Function name: tw_cli_find_aen
399 * Description: Reports whether a given AEN ever occurred.
400 *
401 * Input: ctlr -- ptr to CL internal ctlr context
402 * aen_code-- AEN to look for
403 * Output: None
404 * Return value: 0 -- success
405 * non-zero-- failure
406 */
407 TW_INT32
408 tw_cli_find_aen(struct tw_cli_ctlr_context *ctlr, TW_UINT16 aen_code)
409 {
410 TW_UINT32 last_index;
411 TW_INT32 i;
412
413 tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(), "entered");
414
415 if (ctlr->aen_q_wrapped)
416 last_index = ctlr->aen_head;
417 else
418 last_index = 0;
419
420 i = ctlr->aen_head;
421 do {
422 i = (i + ctlr->max_aens_supported - 1) %
423 ctlr->max_aens_supported;
424 if (ctlr->aen_queue[i].aen_code == aen_code)
425 return(TW_OSL_ESUCCESS);
426 } while (i != last_index);
427
428 return(TW_OSL_EGENFAILURE);
429 }
430
431
432
433 /*
434 * Function name: tw_cli_poll_status
435 * Description: Poll for a given status to show up in the firmware
436 * status register.
437 *
438 * Input: ctlr -- ptr to CL internal ctlr context
439 * status -- status to look for
440 * timeout -- max # of seconds to wait before giving up
441 * Output: None
442 * Return value: 0 -- success
443 * non-zero-- failure
444 */
445 TW_INT32
446 tw_cli_poll_status(struct tw_cli_ctlr_context *ctlr, TW_UINT32 status,
447 TW_UINT32 timeout)
448 {
449 TW_TIME end_time;
450 TW_UINT32 status_reg;
451
452 tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(), "entered");
453
454 end_time = tw_osl_get_local_time() + timeout;
455 do {
456 status_reg = TW_CLI_READ_STATUS_REGISTER(ctlr->ctlr_handle);
457 if ((status_reg & status) == status)
458 /* got the required bit(s) */
459 return(TW_OSL_ESUCCESS);
460
461 /*
462 * The OSL should not define TW_OSL_CAN_SLEEP if it calls
463 * tw_cl_deferred_interrupt from within the ISR and not a
464 * lower interrupt level, since, in that case, we might end
465 * up here, and try to sleep (within an ISR).
466 */
467 #ifndef TW_OSL_CAN_SLEEP
468 /* OSL doesn't support sleeping; will spin. */
469 tw_osl_delay(1000);
470 #else /* TW_OSL_CAN_SLEEP */
471 #if 0
472 /* Will spin if initializing, sleep otherwise. */
473 if (!(ctlr->state & TW_CLI_CTLR_STATE_ACTIVE))
474 tw_osl_delay(1000);
475 else
476 tw_osl_sleep(ctlr->ctlr_handle,
477 &(ctlr->sleep_handle), 1 /* ms */);
478 #else /* #if 0 */
479 /*
480 * Will always spin for now (since reset holds a spin lock).
481 * We could free io_lock after the call to TW_CLI_SOFT_RESET,
482 * so we could sleep here. To block new requests (since
483 * the lock will have been released) we could use the
484 * ...RESET_IN_PROGRESS flag. Need to revisit.
485 */
486 tw_osl_delay(1000);
487 #endif /* #if 0 */
488 #endif /* TW_OSL_CAN_SLEEP */
489 } while (tw_osl_get_local_time() <= end_time);
490
491 return(TW_OSL_ETIMEDOUT);
492 }
493
494
495
496 /*
497 * Function name: tw_cl_create_event
498 * Description: Creates and queues ctlr/CL/OSL AEN's to be
499 * supplied to user-space tools on request.
500 * Also notifies OS Layer.
501 * Input: ctlr -- ptr to CL internal ctlr context
502 * queue_event-- TW_CL_TRUE --> queue event;
503 * TW_CL_FALSE--> don't queue event
504 * (simply notify OSL)
505 * event_src -- source of event
506 * event_code -- AEN/error code
507 * severity -- severity of event
508 * severity_str--Text description of severity
509 * event_desc -- standard string related to the event/error
510 * event_specific_desc -- format string for additional
511 * info about the event
512 * ... -- additional arguments conforming to the format
513 * specified by event_specific_desc
514 * Output: None
515 * Return value: None
516 */
517 TW_VOID
518 tw_cl_create_event(struct tw_cl_ctlr_handle *ctlr_handle,
519 TW_UINT8 queue_event, TW_UINT8 event_src, TW_UINT16 event_code,
520 TW_UINT8 severity, TW_UINT8 *severity_str, TW_UINT8 *event_desc,
521 TW_UINT8 *event_specific_desc, ...)
522 {
523 struct tw_cli_ctlr_context *ctlr = ctlr_handle->cl_ctlr_ctxt;
524 struct tw_cl_event_packet event_pkt;
525 struct tw_cl_event_packet *event;
526 TW_UINT32 aen_head;
527 va_list ap;
528
529 tw_cli_dbg_printf(8, ctlr_handle, tw_osl_cur_func(), "entered");
530
531 if ((ctlr) && (queue_event)) {
532 /* Protect access to ctlr->aen_head. */
533 tw_osl_get_lock(ctlr_handle, ctlr->gen_lock);
534
535 aen_head = ctlr->aen_head;
536 ctlr->aen_head = (aen_head + 1) % ctlr->max_aens_supported;
537
538 /* Queue the event. */
539 event = &(ctlr->aen_queue[aen_head]);
540 tw_osl_memzero(event->parameter_data,
541 sizeof(event->parameter_data));
542
543 if (event->retrieved == TW_CL_AEN_NOT_RETRIEVED)
544 ctlr->aen_q_overflow = TW_CL_TRUE;
545 event->sequence_id = ++(ctlr->aen_cur_seq_id);
546 if ((aen_head + 1) == ctlr->max_aens_supported) {
547 tw_cli_dbg_printf(4, ctlr->ctlr_handle,
548 tw_osl_cur_func(), "AEN queue wrapped");
549 ctlr->aen_q_wrapped = TW_CL_TRUE;
550 }
551
552 /* Free access to ctlr->aen_head. */
553 tw_osl_free_lock(ctlr_handle, ctlr->gen_lock);
554 } else {
555 event = &event_pkt;
556 tw_osl_memzero(event, sizeof(struct tw_cl_event_packet));
557 }
558
559 event->event_src = event_src;
560 event->time_stamp_sec = (TW_UINT32)tw_osl_get_local_time();
561 event->aen_code = event_code;
562 event->severity = severity;
563 tw_osl_strcpy(event->severity_str, severity_str);
564 event->retrieved = TW_CL_AEN_NOT_RETRIEVED;
565
566 va_start(ap, event_specific_desc);
567 tw_osl_vsprintf(event->parameter_data, event_specific_desc, ap);
568 va_end(ap);
569
570 event->parameter_len =
571 (TW_UINT8)(tw_osl_strlen(event->parameter_data));
572 tw_osl_strcpy(event->parameter_data + event->parameter_len + 1,
573 event_desc);
574 event->parameter_len += (1 + tw_osl_strlen(event_desc));
575
576 tw_cli_dbg_printf(4, ctlr_handle, tw_osl_cur_func(),
577 "event = %x %x %x %x %x %x %x\n %s",
578 event->sequence_id,
579 event->time_stamp_sec,
580 event->aen_code,
581 event->severity,
582 event->retrieved,
583 event->repeat_count,
584 event->parameter_len,
585 event->parameter_data);
586
587 tw_osl_notify_event(ctlr_handle, event);
588 }
589
590
591
592 /*
593 * Function name: tw_cli_get_request
594 * Description: Gets a request pkt from the free queue.
595 *
596 * Input: ctlr -- ptr to CL internal ctlr context
597 * req_pkt -- ptr to OSL built req_pkt, if there's one
598 * Output: None
599 * Return value: ptr to request pkt -- success
600 * TW_CL_NULL -- failure
601 */
602 struct tw_cli_req_context *
603 tw_cli_get_request(struct tw_cli_ctlr_context *ctlr
604 #ifdef TW_OSL_NON_DMA_MEM_ALLOC_PER_REQUEST
605 , struct tw_cl_req_packet *req_pkt
606 #endif /* TW_OSL_NON_DMA_MEM_ALLOC_PER_REQUEST */
607 )
608 {
609 struct tw_cli_req_context *req;
610
611 tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(), "entered");
612
613 #ifdef TW_OSL_NON_DMA_MEM_ALLOC_PER_REQUEST
614
615 if (req_pkt) {
616 if (ctlr->num_free_req_ids == 0)
617 return(TW_CL_NULL);
618
619 ctlr->num_free_req_ids--;
620 req = (struct tw_cli_req_context *)(req_pkt->non_dma_mem);
621 req->ctlr = ctlr;
622 req->request_id = ctlr->free_req_ids[ctlr->free_req_head];
623 ctlr->busy_reqs[req->request_id] = req;
624 ctlr->free_req_head = (ctlr->free_req_head + 1) %
625 (ctlr->max_simult_reqs - 1);
626 } else
627
628 #endif /* TW_OSL_NON_DMA_MEM_ALLOC_PER_REQUEST */
629 {
630 /* Get a free request packet. */
631 req = tw_cli_req_q_remove_head(ctlr, TW_CLI_FREE_Q);
632 }
633
634 /* Initialize some fields to their defaults. */
635 if (req) {
636 req->req_handle = TW_CL_NULL;
637 req->data = TW_CL_NULL;
638 req->length = 0;
639 req->data_phys = 0;
640 req->state = TW_CLI_REQ_STATE_INIT; /* req being initialized */
641 req->flags = 0;
642 req->error_code = 0;
643 req->orig_req = TW_CL_NULL;
644 req->tw_cli_callback = TW_CL_NULL;
645
646 #ifndef TW_OSL_DMA_MEM_ALLOC_PER_REQUEST
647
648 /*
649 * Look at the status field in the command packet to see how
650 * it completed the last time it was used, and zero out only
651 * the portions that might have changed. Note that we don't
652 * care to zero out the sglist.
653 */
654 if (req->cmd_pkt->command.cmd_pkt_9k.status)
655 tw_osl_memzero(req->cmd_pkt,
656 sizeof(struct tw_cl_command_header) +
657 28 /* max bytes before sglist */);
658 else
659 tw_osl_memzero(&(req->cmd_pkt->command),
660 28 /* max bytes before sglist */);
661
662 #endif /* TW_OSL_DMA_MEM_ALLOC_PER_REQUEST */
663 }
664 return(req);
665 }
666
667
668
669 /*
670 * Function name: tw_cli_dbg_printf
671 * Description: Calls OSL print function if dbg_level is appropriate
672 *
673 * Input: dbg_level -- Determines whether or not to print
674 * ctlr_handle -- controller handle
675 * cur_func -- text name of calling function
676 * fmt -- format string for the arguments to follow
677 * ... -- variable number of arguments, to be printed
678 * based on the fmt string
679 * Output: None
680 * Return value: None
681 */
682 TW_VOID
683 tw_cli_dbg_printf(TW_UINT8 dbg_level,
684 struct tw_cl_ctlr_handle *ctlr_handle, const TW_INT8 *cur_func,
685 TW_INT8 *fmt, ...)
686 {
687 #ifdef TW_OSL_DEBUG
688 TW_INT8 print_str[256];
689 va_list ap;
690
691 tw_osl_memzero(print_str, 256);
692 if (dbg_level <= TW_OSL_DEBUG_LEVEL_FOR_CL) {
693 tw_osl_sprintf(print_str, "%s: ", cur_func);
694
695 va_start(ap, fmt);
696 tw_osl_vsprintf(print_str + tw_osl_strlen(print_str), fmt, ap);
697 va_end(ap);
698
699 tw_osl_strcpy(print_str + tw_osl_strlen(print_str), "\n");
700 tw_osl_dbg_printf(ctlr_handle, print_str);
701 }
702 #endif /* TW_OSL_DEBUG */
703 }
704
705
706
707 /*
708 * Function name: tw_cli_notify_ctlr_info
709 * Description: Notify OSL of controller info (fw/BIOS versions, etc.).
710 *
711 * Input: ctlr -- ptr to CL internal ctlr context
712 * Output: None
713 * Return value: None
714 */
715 TW_VOID
716 tw_cli_notify_ctlr_info(struct tw_cli_ctlr_context *ctlr)
717 {
718 TW_INT8 fw_ver[16];
719 TW_INT8 bios_ver[16];
720 TW_INT8 ctlr_model[16];
721 TW_INT32 error[3];
722 TW_UINT8 num_ports = 0;
723
724 tw_cli_dbg_printf(5, ctlr->ctlr_handle, tw_osl_cur_func(), "entered");
725
726 /* Get the port count. */
727 error[0] = tw_cli_get_param(ctlr, TWA_PARAM_CONTROLLER_TABLE,
728 TWA_PARAM_CONTROLLER_PORT_COUNT, &num_ports,
729 1, TW_CL_NULL);
730
731 /* Get the firmware and BIOS versions. */
732 error[0] = tw_cli_get_param(ctlr, TWA_PARAM_VERSION_TABLE,
733 TWA_PARAM_VERSION_FW, fw_ver, 16, TW_CL_NULL);
734 error[1] = tw_cli_get_param(ctlr, TWA_PARAM_VERSION_TABLE,
735 TWA_PARAM_VERSION_BIOS, bios_ver, 16, TW_CL_NULL);
736 error[2] = tw_cli_get_param(ctlr, TWA_PARAM_VERSION_TABLE,
737 TWA_PARAM_CTLR_MODEL, ctlr_model, 16, TW_CL_NULL);
738
739 tw_cl_create_event(ctlr->ctlr_handle, TW_CL_FALSE,
740 TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR,
741 0x1300, 0x3, TW_CL_SEVERITY_INFO_STRING,
742 "Controller details:",
743 "Model %.16s, %d ports, Firmware %.16s, BIOS %.16s",
744 error[2]?(TW_INT8 *)TW_CL_NULL:ctlr_model,
745 num_ports,
746 error[0]?(TW_INT8 *)TW_CL_NULL:fw_ver,
747 error[1]?(TW_INT8 *)TW_CL_NULL:bios_ver);
748 }
749
750
751
752 /*
753 * Function name: tw_cli_check_ctlr_state
754 * Description: Makes sure that the fw status register reports a
755 * proper status.
756 *
757 * Input: ctlr -- ptr to CL internal ctlr context
758 * status_reg-- value in the status register
759 * Output: None
760 * Return value: 0 -- no errors
761 * non-zero-- errors
762 */
763 TW_INT32
764 tw_cli_check_ctlr_state(struct tw_cli_ctlr_context *ctlr, TW_UINT32 status_reg)
765 {
766 struct tw_cl_ctlr_handle *ctlr_handle = ctlr->ctlr_handle;
767 TW_INT32 error = TW_OSL_ESUCCESS;
768
769 tw_cli_dbg_printf(8, ctlr->ctlr_handle, tw_osl_cur_func(), "entered");
770
771 /* Check if the 'micro-controller ready' bit is not set. */
772 if ((status_reg & TWA_STATUS_EXPECTED_BITS) !=
773 TWA_STATUS_EXPECTED_BITS) {
774 TW_INT8 desc[200];
775
776 tw_osl_memzero(desc, 200);
777 if ((status_reg & TWA_STATUS_MICROCONTROLLER_READY) ||
778 (!(ctlr->state &
779 TW_CLI_CTLR_STATE_RESET_PHASE1_IN_PROGRESS))) {
780 tw_cl_create_event(ctlr_handle, TW_CL_TRUE,
781 TW_CL_MESSAGE_SOURCE_COMMON_LAYER_EVENT,
782 0x1301, 0x1, TW_CL_SEVERITY_ERROR_STRING,
783 "Missing expected status bit(s)",
784 "status reg = 0x%x; Missing bits: %s",
785 status_reg,
786 tw_cli_describe_bits (~status_reg &
787 TWA_STATUS_EXPECTED_BITS, desc));
788 error = TW_OSL_EGENFAILURE;
789 }
790 }
791
792 /* Check if any error bits are set. */
793 if ((status_reg & TWA_STATUS_UNEXPECTED_BITS) != 0) {
794 TW_INT8 desc[200];
795
796 tw_osl_memzero(desc, 200);
797 tw_cl_create_event(ctlr_handle, TW_CL_TRUE,
798 TW_CL_MESSAGE_SOURCE_COMMON_LAYER_EVENT,
799 0x1302, 0x1, TW_CL_SEVERITY_ERROR_STRING,
800 "Unexpected status bit(s)",
801 "status reg = 0x%x Unexpected bits: %s",
802 status_reg & TWA_STATUS_UNEXPECTED_BITS,
803 tw_cli_describe_bits(status_reg &
804 TWA_STATUS_UNEXPECTED_BITS, desc));
805
806 if (status_reg & TWA_STATUS_PCI_PARITY_ERROR_INTERRUPT) {
807 tw_cl_create_event(ctlr_handle, TW_CL_TRUE,
808 TW_CL_MESSAGE_SOURCE_COMMON_LAYER_EVENT,
809 0x1303, 0x1, TW_CL_SEVERITY_ERROR_STRING,
810 "PCI parity error: clearing... "
811 "Re-seat/move/replace card",
812 "status reg = 0x%x %s",
813 status_reg,
814 tw_cli_describe_bits(status_reg, desc));
815 TW_CLI_WRITE_CONTROL_REGISTER(ctlr->ctlr_handle,
816 TWA_CONTROL_CLEAR_PARITY_ERROR);
817
818 #ifdef TW_OSL_PCI_CONFIG_ACCESSIBLE
819 tw_osl_write_pci_config(ctlr->ctlr_handle,
820 TW_CLI_PCI_CONFIG_STATUS_OFFSET,
821 TWA_PCI_CONFIG_CLEAR_PARITY_ERROR, 2);
822 #endif /* TW_OSL_PCI_CONFIG_ACCESSIBLE */
823
824 }
825
826 if (status_reg & TWA_STATUS_PCI_ABORT_INTERRUPT) {
827 tw_cl_create_event(ctlr_handle, TW_CL_TRUE,
828 TW_CL_MESSAGE_SOURCE_COMMON_LAYER_EVENT,
829 0x1304, 0x1, TW_CL_SEVERITY_ERROR_STRING,
830 "PCI abort: clearing... ",
831 "status reg = 0x%x %s",
832 status_reg,
833 tw_cli_describe_bits(status_reg, desc));
834 TW_CLI_WRITE_CONTROL_REGISTER(ctlr->ctlr_handle,
835 TWA_CONTROL_CLEAR_PCI_ABORT);
836
837 #ifdef TW_OSL_PCI_CONFIG_ACCESSIBLE
838 tw_osl_write_pci_config(ctlr->ctlr_handle,
839 TW_CLI_PCI_CONFIG_STATUS_OFFSET,
840 TWA_PCI_CONFIG_CLEAR_PCI_ABORT, 2);
841 #endif /* TW_OSL_PCI_CONFIG_ACCESSIBLE */
842
843 }
844
845 if (status_reg & TWA_STATUS_QUEUE_ERROR_INTERRUPT) {
846 tw_cl_create_event(ctlr_handle, TW_CL_TRUE,
847 TW_CL_MESSAGE_SOURCE_COMMON_LAYER_EVENT,
848 0x1305, 0x1, TW_CL_SEVERITY_ERROR_STRING,
849 "Controller queue error: clearing... ",
850 "status reg = 0x%x %s",
851 status_reg,
852 tw_cli_describe_bits(status_reg, desc));
853 TW_CLI_WRITE_CONTROL_REGISTER(ctlr->ctlr_handle,
854 TWA_CONTROL_CLEAR_QUEUE_ERROR);
855 }
856
857 if (status_reg & TWA_STATUS_MICROCONTROLLER_ERROR) {
858 tw_cl_create_event(ctlr_handle, TW_CL_TRUE,
859 TW_CL_MESSAGE_SOURCE_COMMON_LAYER_EVENT,
860 0x1307, 0x1, TW_CL_SEVERITY_ERROR_STRING,
861 "Micro-controller error! ",
862 "status reg = 0x%x %s",
863 status_reg,
864 tw_cli_describe_bits(status_reg, desc));
865 error = TW_OSL_EGENFAILURE;
866 }
867 }
868 return(error);
869 }
870
871
872
873 /*
874 * Function name: tw_cli_describe_bits
875 * Description: Given the value of the status register, returns a
876 * string describing the meaning of each set bit.
877 *
878 * Input: reg -- status register value
879 * Output: Pointer to a string describing each set bit
880 * Return value: Pointer to the string describing each set bit
881 */
882 TW_INT8 *
883 tw_cli_describe_bits(TW_UINT32 reg, TW_INT8 *str)
884 {
885 tw_osl_strcpy(str, "[");
886
887 if (reg & TWA_STATUS_COMMAND_QUEUE_EMPTY)
888 tw_osl_strcpy(&str[tw_osl_strlen(str)], "CMD_Q_EMPTY,");
889 if (reg & TWA_STATUS_MICROCONTROLLER_READY)
890 tw_osl_strcpy(&str[tw_osl_strlen(str)], "MC_RDY,");
891 if (reg & TWA_STATUS_RESPONSE_QUEUE_EMPTY)
892 tw_osl_strcpy(&str[tw_osl_strlen(str)], "RESP_Q_EMPTY,");
893 if (reg & TWA_STATUS_COMMAND_QUEUE_FULL)
894 tw_osl_strcpy(&str[tw_osl_strlen(str)], "CMD_Q_FULL,");
895 if (reg & TWA_STATUS_RESPONSE_INTERRUPT)
896 tw_osl_strcpy(&str[tw_osl_strlen(str)], "RESP_INTR,");
897 if (reg & TWA_STATUS_COMMAND_INTERRUPT)
898 tw_osl_strcpy(&str[tw_osl_strlen(str)], "CMD_INTR,");
899 if (reg & TWA_STATUS_ATTENTION_INTERRUPT)
900 tw_osl_strcpy(&str[tw_osl_strlen(str)], "ATTN_INTR,");
901 if (reg & TWA_STATUS_HOST_INTERRUPT)
902 tw_osl_strcpy(&str[tw_osl_strlen(str)], "HOST_INTR,");
903 if (reg & TWA_STATUS_PCI_ABORT_INTERRUPT)
904 tw_osl_strcpy(&str[tw_osl_strlen(str)], "PCI_ABRT,");
905 if (reg & TWA_STATUS_MICROCONTROLLER_ERROR)
906 tw_osl_strcpy(&str[tw_osl_strlen(str)], "MC_ERR,");
907 if (reg & TWA_STATUS_QUEUE_ERROR_INTERRUPT)
908 tw_osl_strcpy(&str[tw_osl_strlen(str)], "Q_ERR,");
909 if (reg & TWA_STATUS_PCI_PARITY_ERROR_INTERRUPT)
910 tw_osl_strcpy(&str[tw_osl_strlen(str)], "PCI_PERR");
911
912 tw_osl_strcpy(&str[tw_osl_strlen(str)], "]");
913 return(str);
914 }
915
916
917
918 #ifdef TW_OSL_DEBUG
919
920 /*
921 * Function name: tw_cl_print_ctlr_stats
922 * Description: Prints the current status of the controller.
923 *
924 * Input: ctlr_handle-- controller handle
925 * Output: None
926 * Return value: None
927 */
928 TW_VOID
929 tw_cl_print_ctlr_stats(struct tw_cl_ctlr_handle *ctlr_handle)
930 {
931 struct tw_cli_ctlr_context *ctlr =
932 (struct tw_cli_ctlr_context *)(ctlr_handle->cl_ctlr_ctxt);
933 TW_UINT32 status_reg;
934 TW_INT8 desc[200];
935
936 tw_cli_dbg_printf(7, ctlr->ctlr_handle, "", "entered");
937
938 /* Print current controller details. */
939 tw_cli_dbg_printf(0, ctlr_handle, "", "cl_ctlr_ctxt = %p", ctlr);
940
941 tw_osl_memzero(desc, 200);
942 status_reg = TW_CLI_READ_STATUS_REGISTER(ctlr_handle);
943 tw_cli_dbg_printf(0, ctlr_handle, "", "status reg = 0x%x %s",
944 status_reg, tw_cli_describe_bits(status_reg, desc));
945
946 tw_cli_dbg_printf(0, ctlr_handle, "", "CLq type current max");
947 tw_cli_dbg_printf(0, ctlr_handle, "", "free %04d %04d",
948 ctlr->q_stats[TW_CLI_FREE_Q].cur_len,
949 ctlr->q_stats[TW_CLI_FREE_Q].max_len);
950 tw_cli_dbg_printf(0, ctlr_handle, "", "busy %04d %04d",
951 ctlr->q_stats[TW_CLI_BUSY_Q].cur_len,
952 ctlr->q_stats[TW_CLI_BUSY_Q].max_len);
953 tw_cli_dbg_printf(0, ctlr_handle, "", "pending %04d %04d",
954 ctlr->q_stats[TW_CLI_PENDING_Q].cur_len,
955 ctlr->q_stats[TW_CLI_PENDING_Q].max_len);
956 tw_cli_dbg_printf(0, ctlr_handle, "", "complete %04d %04d",
957 ctlr->q_stats[TW_CLI_COMPLETE_Q].cur_len,
958 ctlr->q_stats[TW_CLI_COMPLETE_Q].max_len);
959 tw_cli_dbg_printf(0, ctlr_handle, "", "AEN queue head %d tail %d",
960 ctlr->aen_head, ctlr->aen_tail);
961 }
962
963
964
965 /*
966 * Function name: tw_cl_reset_stats
967 * Description: Resets CL maintained statistics for the controller.
968 *
969 * Input: ctlr_handle-- controller handle
970 * Output: None
971 * Return value: None
972 */
973 TW_VOID
974 tw_cl_reset_stats(struct tw_cl_ctlr_handle *ctlr_handle)
975 {
976 struct tw_cli_ctlr_context *ctlr =
977 (struct tw_cli_ctlr_context *)(ctlr_handle->cl_ctlr_ctxt);
978
979 tw_cli_dbg_printf(7, ctlr_handle, tw_osl_cur_func(), "entered");
980 ctlr->q_stats[TW_CLI_FREE_Q].max_len = 0;
981 ctlr->q_stats[TW_CLI_BUSY_Q].max_len = 0;
982 ctlr->q_stats[TW_CLI_PENDING_Q].max_len = 0;
983 ctlr->q_stats[TW_CLI_COMPLETE_Q].max_len = 0;
984 }
985
986
987
988 /*
989 * Function name: tw_cli_print_req_info
990 * Description: Prints CL internal details of a given request.
991 *
992 * Input: req -- ptr to CL internal request context
993 * Output: None
994 * Return value: None
995 */
996 TW_VOID
997 tw_cl_print_req_info(struct tw_cl_req_handle *req_handle)
998 {
999 struct tw_cli_req_context *req = req_handle->cl_req_ctxt;
1000 struct tw_cli_ctlr_context *ctlr = req->ctlr;
1001 struct tw_cl_ctlr_handle *ctlr_handle = ctlr->ctlr_handle;
1002 struct tw_cl_command_packet *cmd_pkt = req->cmd_pkt;
1003 struct tw_cl_command_9k *cmd9k;
1004 union tw_cl_command_7k *cmd7k;
1005 TW_UINT8 *cdb;
1006 TW_VOID *sgl;
1007 TW_UINT32 sgl_entries;
1008 TW_UINT32 i;
1009
1010 tw_cli_dbg_printf(0, ctlr_handle, tw_osl_cur_func(),
1011 "CL details for request:");
1012 tw_cli_dbg_printf(0, ctlr_handle, tw_osl_cur_func(),
1013 "req_handle = %p, ctlr = %p,\n"
1014 "cmd_pkt = %p, cmd_pkt_phys = 0x%llx,\n"
1015 "data = %p, length = 0x%x, data_phys = 0x%llx,\n"
1016 "state = 0x%x, flags = 0x%x, error = 0x%x,\n"
1017 "orig_req = %p, callback = %p, req_id = 0x%x,\n"
1018 "next_req = %p, prev_req = %p",
1019 req_handle, ctlr,
1020 cmd_pkt, req->cmd_pkt_phys,
1021 req->data, req->length, req->data_phys,
1022 req->state, req->flags, req->error_code,
1023 req->orig_req, req->tw_cli_callback, req->request_id,
1024 req->link.next, req->link.prev);
1025
1026 if (req->flags & TW_CLI_REQ_FLAGS_9K) {
1027 cmd9k = &(cmd_pkt->command.cmd_pkt_9k);
1028 sgl = cmd9k->sg_list;
1029 sgl_entries = TW_CL_SWAP16(
1030 GET_SGL_ENTRIES(cmd9k->lun_h4__sgl_entries));
1031 tw_cli_dbg_printf(0, ctlr_handle, tw_osl_cur_func(),
1032 "9K cmd: opcode = 0x%x, unit = 0x%x, req_id = 0x%x,\n"
1033 "status = 0x%x, sgl_offset = 0x%x, sgl_entries = 0x%x",
1034 GET_OPCODE(cmd9k->res__opcode),
1035 cmd9k->unit,
1036 TW_CL_SWAP16(GET_REQ_ID(cmd9k->lun_l4__req_id)),
1037 cmd9k->status,
1038 cmd9k->sgl_offset,
1039 sgl_entries);
1040
1041 cdb = (TW_UINT8 *)(cmd9k->cdb);
1042 tw_cli_dbg_printf(0, ctlr_handle, tw_osl_cur_func(),
1043 "CDB: %x %x %x %x %x %x %x %x"
1044 "%x %x %x %x %x %x %x %x",
1045 cdb[0], cdb[1], cdb[2], cdb[3],
1046 cdb[4], cdb[5], cdb[6], cdb[7],
1047 cdb[8], cdb[9], cdb[10], cdb[11],
1048 cdb[12], cdb[13], cdb[14], cdb[15]);
1049 } else {
1050 cmd7k = &(cmd_pkt->command.cmd_pkt_7k);
1051 sgl = cmd7k->param.sgl;
1052 sgl_entries = (cmd7k->generic.size -
1053 GET_SGL_OFF(cmd7k->generic.sgl_off__opcode)) /
1054 ((ctlr->flags & TW_CL_64BIT_ADDRESSES) ? 3 : 2);
1055 tw_cli_dbg_printf(0, ctlr_handle, tw_osl_cur_func(),
1056 "7K cmd: opcode = 0x%x, sgl_offset = 0x%x,\n"
1057 "size = 0x%x, req_id = 0x%x, unit = 0x%x,\n"
1058 "status = 0x%x, flags = 0x%x, count = 0x%x",
1059 GET_OPCODE(cmd7k->generic.sgl_off__opcode),
1060 GET_SGL_OFF(cmd7k->generic.sgl_off__opcode),
1061 cmd7k->generic.size,
1062 TW_CL_SWAP16(cmd7k->generic.request_id),
1063 GET_UNIT(cmd7k->generic.host_id__unit),
1064 cmd7k->generic.status,
1065 cmd7k->generic.flags,
1066 TW_CL_SWAP16(cmd7k->generic.count));
1067 }
1068
1069 tw_cli_dbg_printf(0, ctlr_handle, tw_osl_cur_func(), "SG entries:");
1070
1071 if (ctlr->flags & TW_CL_64BIT_ADDRESSES) {
1072 struct tw_cl_sg_desc64 *sgl64 = (struct tw_cl_sg_desc64 *)sgl;
1073
1074 for (i = 0; i < sgl_entries; i++) {
1075 tw_cli_dbg_printf(0, ctlr_handle, tw_osl_cur_func(),
1076 "0x%llx 0x%x",
1077 sgl64[i].address, sgl64[i].length);
1078 }
1079 } else {
1080 struct tw_cl_sg_desc32 *sgl32 = (struct tw_cl_sg_desc32 *)sgl;
1081
1082 for (i = 0; i < sgl_entries; i++) {
1083 tw_cli_dbg_printf(0, ctlr_handle, tw_osl_cur_func(),
1084 "0x%x 0x%x",
1085 sgl32[i].address, sgl32[i].length);
1086 }
1087 }
1088 }
1089
1090 #endif /* TW_OSL_DEBUG */
1091
Cache object: 5fffb57eb7092556663f8441de70de24
|