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