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