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