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 242827 2012-11-09 15:29:52Z rdivacky $ 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 TW_CL_NULL) { 88 if (req->flags & TW_CLI_REQ_FLAGS_INTERNAL) { 89 /* 90 * It's an internal request. Set the appropriate 91 * error and call the CL internal callback if there's 92 * one. If the request originator is polling for 93 * completion, he should be checking req->error to 94 * determine that the request did not go through. 95 * The request originators are responsible for the 96 * clean-up. 97 */ 98 req->error_code = TW_CL_ERR_REQ_BUS_RESET; 99 if (req->tw_cli_callback) 100 req->tw_cli_callback(req); 101 } else if (req->flags & TW_CLI_REQ_FLAGS_PASSTHRU) { 102 /* It's a passthru request. Complete it. */ 103 if ((req_pkt = req->orig_req) != TW_CL_NULL) { 104 req_pkt->status = TW_CL_ERR_REQ_BUS_RESET; 105 106 if (req_pkt->tw_osl_callback) 107 req_pkt->tw_osl_callback(req->req_handle); 108 } 109 tw_cli_req_q_insert_tail(req, TW_CLI_FREE_Q); 110 } else { 111 /* It's an external (SCSI) request. Add it to the reset queue. */ 112 tw_osl_untimeout(req->req_handle); 113 tw_cli_req_q_insert_tail(req, TW_CLI_RESET_Q); 114 } 115 } /* End of while loop */ 116 } 117 118 119 120 /* 121 * Function name: tw_cli_drain_busy_queue 122 * Description: This function gets called during a controller reset. 123 * It errors back to the OS Layer, all those requests that 124 * were pending with the firmware, at the time of the 125 * reset. 126 * 127 * Input: ctlr -- ptr to CL internal ctlr context 128 * Output: None 129 * Return value: None 130 */ 131 TW_VOID 132 tw_cli_drain_busy_queue(struct tw_cli_ctlr_context *ctlr) 133 { 134 struct tw_cli_req_context *req; 135 struct tw_cl_req_packet *req_pkt; 136 137 tw_cli_dbg_printf(3, ctlr->ctlr_handle, tw_osl_cur_func(), "entered"); 138 139 /* Walk the busy queue. */ 140 while ((req = tw_cli_req_q_remove_head(ctlr, TW_CLI_BUSY_Q)) != 141 TW_CL_NULL) { 142 if (req->flags & TW_CLI_REQ_FLAGS_INTERNAL) { 143 /* 144 * It's an internal request. Set the appropriate 145 * error and call the CL internal callback if there's 146 * one. If the request originator is polling for 147 * completion, he should be checking req->error to 148 * determine that the request did not go through. 149 * The request originators are responsible for the 150 * clean-up. 151 */ 152 req->error_code = TW_CL_ERR_REQ_BUS_RESET; 153 if (req->tw_cli_callback) 154 req->tw_cli_callback(req); 155 } else if (req->flags & TW_CLI_REQ_FLAGS_PASSTHRU) { 156 /* It's a passthru request. Complete it. */ 157 if ((req_pkt = req->orig_req) != TW_CL_NULL) { 158 req_pkt->status = TW_CL_ERR_REQ_BUS_RESET; 159 160 if (req_pkt->tw_osl_callback) 161 req_pkt->tw_osl_callback(req->req_handle); 162 } 163 tw_cli_req_q_insert_tail(req, TW_CLI_FREE_Q); 164 } else { 165 /* It's an external (SCSI) request. Add it to the reset queue. */ 166 tw_osl_untimeout(req->req_handle); 167 tw_cli_req_q_insert_tail(req, TW_CLI_RESET_Q); 168 } 169 } /* End of while loop */ 170 } 171 172 173 174 /* 175 * Function name: tw_cli_drain_pending_queue 176 * Description: This function gets called during a controller reset. 177 * It errors back to the OS Layer, all those requests that 178 * were in the pending queue, at the time of the reset. 179 * 180 * Input: ctlr -- ptr to CL internal ctlr context 181 * Output: None 182 * Return value: None 183 */ 184 185 TW_VOID 186 tw_cli_drain_pending_queue(struct tw_cli_ctlr_context *ctlr) 187 { 188 struct tw_cli_req_context *req; 189 struct tw_cl_req_packet *req_pkt; 190 191 tw_cli_dbg_printf(3, ctlr->ctlr_handle, tw_osl_cur_func(), "entered"); 192 193 /* 194 * Pull requests off the pending queue, and complete them. 195 */ 196 while ((req = tw_cli_req_q_remove_head(ctlr, TW_CLI_PENDING_Q)) != 197 TW_CL_NULL) { 198 if (req->flags & TW_CLI_REQ_FLAGS_INTERNAL) { 199 /* 200 * It's an internal request. Set the appropriate 201 * error and call the CL internal callback if there's 202 * one. If the request originator is polling for 203 * completion, he should be checking req->error to 204 * determine that the request did not go through. 205 * The request originators are responsible for the 206 * clean-up. 207 */ 208 req->error_code = TW_CL_ERR_REQ_BUS_RESET; 209 if (req->tw_cli_callback) 210 req->tw_cli_callback(req); 211 } else if (req->flags & TW_CLI_REQ_FLAGS_PASSTHRU) { 212 /* It's a passthru request. Complete it. */ 213 if ((req_pkt = req->orig_req) != TW_CL_NULL) { 214 req_pkt->status = TW_CL_ERR_REQ_BUS_RESET; 215 216 if (req_pkt->tw_osl_callback) 217 req_pkt->tw_osl_callback(req->req_handle); 218 } 219 tw_cli_req_q_insert_tail(req, TW_CLI_FREE_Q); 220 } else { 221 /* It's an external (SCSI) request. Add it to the reset queue. */ 222 tw_osl_untimeout(req->req_handle); 223 tw_cli_req_q_insert_tail(req, TW_CLI_RESET_Q); 224 } 225 } /* End of while loop */ 226 } 227 228 229 230 /* 231 * Function name: tw_cli_drain_response_queue 232 * Description: Drain the controller response queue. 233 * 234 * Input: ctlr -- ptr to per ctlr structure 235 * Output: None 236 * Return value: 0 -- success 237 * non-zero-- failure 238 */ 239 TW_INT32 240 tw_cli_drain_response_queue(struct tw_cli_ctlr_context *ctlr) 241 { 242 TW_UINT32 resp; 243 TW_UINT32 status_reg; 244 245 tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(), "entered"); 246 247 for (;;) { 248 status_reg = TW_CLI_READ_STATUS_REGISTER(ctlr->ctlr_handle); 249 250 if (status_reg & TWA_STATUS_RESPONSE_QUEUE_EMPTY) 251 return(TW_OSL_ESUCCESS); /* no more response queue entries */ 252 253 resp = TW_CLI_READ_RESPONSE_QUEUE(ctlr->ctlr_handle); 254 } 255 } 256 257 258 259 /* 260 * Function name: tw_cli_find_response 261 * Description: Find a particular response in the ctlr response queue. 262 * 263 * Input: ctlr -- ptr to per ctlr structure 264 * req_id -- request id of the response to look for 265 * Output: None 266 * Return value: 0 -- success 267 * non-zero-- failure 268 */ 269 TW_INT32 270 tw_cli_find_response(struct tw_cli_ctlr_context *ctlr, TW_INT32 req_id) 271 { 272 TW_UINT32 resp; 273 TW_INT32 resp_id; 274 TW_UINT32 status_reg; 275 276 tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(), "entered"); 277 278 for (;;) { 279 status_reg = TW_CLI_READ_STATUS_REGISTER(ctlr->ctlr_handle); 280 281 if (status_reg & TWA_STATUS_RESPONSE_QUEUE_EMPTY) 282 return(TW_OSL_ENOTTY); /* no more response queue entries */ 283 284 if (ctlr->device_id == TW_CL_DEVICE_ID_9K) { 285 resp = TW_CLI_READ_RESPONSE_QUEUE(ctlr->ctlr_handle); 286 resp_id = GET_RESP_ID(resp); 287 } else { 288 resp = TW_CLI_READ_LARGE_RESPONSE_QUEUE( 289 ctlr->ctlr_handle); 290 resp_id = GET_LARGE_RESP_ID(resp); 291 } 292 if (resp_id == req_id) 293 return(TW_OSL_ESUCCESS); /* found the req_id */ 294 } 295 } 296 297 298 299 /* 300 * Function name: tw_cli_drain_aen_queue 301 * Description: Fetches all un-retrieved AEN's posted by fw. 302 * 303 * Input: ctlr -- ptr to CL internal ctlr context 304 * Output: None 305 * Return value: 0 -- success 306 * non-zero-- failure 307 */ 308 TW_INT32 309 tw_cli_drain_aen_queue(struct tw_cli_ctlr_context *ctlr) 310 { 311 struct tw_cli_req_context *req; 312 TW_TIME end_time; 313 TW_UINT16 aen_code; 314 TW_INT32 error; 315 316 tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(), "entered"); 317 318 for (;;) { 319 if ((req = tw_cli_get_request(ctlr 320 )) == TW_CL_NULL) { 321 error = TW_OSL_EBUSY; 322 break; 323 } 324 325 req->flags |= TW_CLI_REQ_FLAGS_INTERNAL; 326 req->tw_cli_callback = TW_CL_NULL; 327 if ((error = tw_cli_send_scsi_cmd(req, 328 0x03 /* REQUEST_SENSE */))) { 329 tw_cli_dbg_printf(1, ctlr->ctlr_handle, 330 tw_osl_cur_func(), 331 "Cannot send command to fetch aen"); 332 break; 333 } 334 335 end_time = tw_osl_get_local_time() + 336 TW_CLI_REQUEST_TIMEOUT_PERIOD; 337 do { 338 if ((error = req->error_code)) 339 /* 340 * This will take care of completion due to 341 * a reset, or a failure in 342 * tw_cli_submit_pending_queue. 343 */ 344 goto out; 345 346 tw_cli_process_resp_intr(req->ctlr); 347 348 if ((req->state != TW_CLI_REQ_STATE_BUSY) && 349 (req->state != TW_CLI_REQ_STATE_PENDING)) 350 break; 351 } while (tw_osl_get_local_time() <= end_time); 352 353 if (req->state != TW_CLI_REQ_STATE_COMPLETE) { 354 error = TW_OSL_ETIMEDOUT; 355 break; 356 } 357 358 if ((error = req->cmd_pkt->command.cmd_pkt_9k.status)) { 359 #if 0 360 struct tw_cl_command_header *cmd_hdr; 361 cmd_hdr = &req->cmd_pkt->cmd_hdr; 362 tw_cli_create_ctlr_event(ctlr, 363 TW_CL_MESSAGE_SOURCE_CONTROLLER_ERROR, 364 cmd_hdr); 365 #endif // 0 366 break; 367 } 368 369 aen_code = tw_cli_manage_aen(ctlr, req); 370 if (aen_code == TWA_AEN_QUEUE_EMPTY) 371 break; 372 if (aen_code == TWA_AEN_SYNC_TIME_WITH_HOST) 373 continue; 374 375 ctlr->internal_req_busy = TW_CL_FALSE; 376 tw_cli_req_q_insert_tail(req, TW_CLI_FREE_Q); 377 } 378 379 out: 380 if (req) { 381 if (req->data) 382 ctlr->internal_req_busy = TW_CL_FALSE; 383 tw_cli_req_q_insert_tail(req, TW_CLI_FREE_Q); 384 } 385 return(error); 386 } 387 388 389 390 /* 391 * Function name: tw_cli_find_aen 392 * Description: Reports whether a given AEN ever occurred. 393 * 394 * Input: ctlr -- ptr to CL internal ctlr context 395 * aen_code-- AEN to look for 396 * Output: None 397 * Return value: 0 -- success 398 * non-zero-- failure 399 */ 400 TW_INT32 401 tw_cli_find_aen(struct tw_cli_ctlr_context *ctlr, TW_UINT16 aen_code) 402 { 403 TW_UINT32 last_index; 404 TW_INT32 i; 405 406 tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(), "entered"); 407 408 if (ctlr->aen_q_wrapped) 409 last_index = ctlr->aen_head; 410 else 411 last_index = 0; 412 413 i = ctlr->aen_head; 414 do { 415 i = (i + ctlr->max_aens_supported - 1) % 416 ctlr->max_aens_supported; 417 if (ctlr->aen_queue[i].aen_code == aen_code) 418 return(TW_OSL_ESUCCESS); 419 } while (i != last_index); 420 421 return(TW_OSL_EGENFAILURE); 422 } 423 424 425 426 /* 427 * Function name: tw_cli_poll_status 428 * Description: Poll for a given status to show up in the firmware 429 * status register. 430 * 431 * Input: ctlr -- ptr to CL internal ctlr context 432 * status -- status to look for 433 * timeout -- max # of seconds to wait before giving up 434 * Output: None 435 * Return value: 0 -- success 436 * non-zero-- failure 437 */ 438 TW_INT32 439 tw_cli_poll_status(struct tw_cli_ctlr_context *ctlr, TW_UINT32 status, 440 TW_UINT32 timeout) 441 { 442 TW_TIME end_time; 443 TW_UINT32 status_reg; 444 445 tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(), "entered"); 446 447 end_time = tw_osl_get_local_time() + timeout; 448 do { 449 status_reg = TW_CLI_READ_STATUS_REGISTER(ctlr->ctlr_handle); 450 if ((status_reg & status) == status) 451 /* got the required bit(s) */ 452 return(TW_OSL_ESUCCESS); 453 454 tw_osl_delay(1000); 455 } while (tw_osl_get_local_time() <= end_time); 456 457 return(TW_OSL_ETIMEDOUT); 458 } 459 460 461 462 /* 463 * Function name: tw_cl_create_event 464 * Description: Creates and queues ctlr/CL/OSL AEN's to be 465 * supplied to user-space tools on request. 466 * Also notifies OS Layer. 467 * Input: ctlr -- ptr to CL internal ctlr context 468 * queue_event-- TW_CL_TRUE --> queue event; 469 * TW_CL_FALSE--> don't queue event 470 * (simply notify OSL) 471 * event_src -- source of event 472 * event_code -- AEN/error code 473 * severity -- severity of event 474 * severity_str--Text description of severity 475 * event_desc -- standard string related to the event/error 476 * event_specific_desc -- format string for additional 477 * info about the event 478 * ... -- additional arguments conforming to the format 479 * specified by event_specific_desc 480 * Output: None 481 * Return value: None 482 */ 483 TW_VOID 484 tw_cl_create_event(struct tw_cl_ctlr_handle *ctlr_handle, 485 TW_UINT8 queue_event, TW_UINT8 event_src, TW_UINT16 event_code, 486 TW_UINT8 severity, TW_UINT8 *severity_str, TW_UINT8 *event_desc, 487 TW_UINT8 *event_specific_desc, ...) 488 { 489 struct tw_cli_ctlr_context *ctlr = ctlr_handle->cl_ctlr_ctxt; 490 struct tw_cl_event_packet event_pkt; 491 struct tw_cl_event_packet *event; 492 TW_UINT32 aen_head; 493 va_list ap; 494 495 tw_cli_dbg_printf(8, ctlr_handle, tw_osl_cur_func(), "entered"); 496 497 if ((ctlr) && (queue_event)) { 498 /* Protect access to ctlr->aen_head. */ 499 tw_osl_get_lock(ctlr_handle, ctlr->gen_lock); 500 501 aen_head = ctlr->aen_head; 502 ctlr->aen_head = (aen_head + 1) % ctlr->max_aens_supported; 503 504 /* Queue the event. */ 505 event = &(ctlr->aen_queue[aen_head]); 506 tw_osl_memzero(event->parameter_data, 507 sizeof(event->parameter_data)); 508 509 if (event->retrieved == TW_CL_AEN_NOT_RETRIEVED) 510 ctlr->aen_q_overflow = TW_CL_TRUE; 511 event->sequence_id = ++(ctlr->aen_cur_seq_id); 512 if ((aen_head + 1) == ctlr->max_aens_supported) { 513 tw_cli_dbg_printf(4, ctlr->ctlr_handle, 514 tw_osl_cur_func(), "AEN queue wrapped"); 515 ctlr->aen_q_wrapped = TW_CL_TRUE; 516 } 517 518 /* Free access to ctlr->aen_head. */ 519 tw_osl_free_lock(ctlr_handle, ctlr->gen_lock); 520 } else { 521 event = &event_pkt; 522 tw_osl_memzero(event, sizeof(struct tw_cl_event_packet)); 523 } 524 525 event->event_src = event_src; 526 event->time_stamp_sec = (TW_UINT32)tw_osl_get_local_time(); 527 event->aen_code = event_code; 528 event->severity = severity; 529 tw_osl_strcpy(event->severity_str, severity_str); 530 event->retrieved = TW_CL_AEN_NOT_RETRIEVED; 531 532 va_start(ap, event_specific_desc); 533 tw_osl_vsprintf(event->parameter_data, event_specific_desc, ap); 534 va_end(ap); 535 536 event->parameter_len = 537 (TW_UINT8)(tw_osl_strlen(event->parameter_data)); 538 tw_osl_strcpy(event->parameter_data + event->parameter_len + 1, 539 event_desc); 540 event->parameter_len += (1 + tw_osl_strlen(event_desc)); 541 542 tw_cli_dbg_printf(4, ctlr_handle, tw_osl_cur_func(), 543 "event = %x %x %x %x %x %x %x\n %s", 544 event->sequence_id, 545 event->time_stamp_sec, 546 event->aen_code, 547 event->severity, 548 event->retrieved, 549 event->repeat_count, 550 event->parameter_len, 551 event->parameter_data); 552 553 tw_osl_notify_event(ctlr_handle, event); 554 } 555 556 557 558 /* 559 * Function name: tw_cli_get_request 560 * Description: Gets a request pkt from the free queue. 561 * 562 * Input: ctlr -- ptr to CL internal ctlr context 563 * req_pkt -- ptr to OSL built req_pkt, if there's one 564 * Output: None 565 * Return value: ptr to request pkt -- success 566 * TW_CL_NULL -- failure 567 */ 568 struct tw_cli_req_context * 569 tw_cli_get_request(struct tw_cli_ctlr_context *ctlr 570 ) 571 { 572 struct tw_cli_req_context *req; 573 574 tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(), "entered"); 575 576 { 577 /* Get a free request packet. */ 578 req = tw_cli_req_q_remove_head(ctlr, TW_CLI_FREE_Q); 579 } 580 581 /* Initialize some fields to their defaults. */ 582 if (req) { 583 req->req_handle = TW_CL_NULL; 584 req->data = TW_CL_NULL; 585 req->length = 0; 586 req->data_phys = 0; 587 req->state = TW_CLI_REQ_STATE_INIT; /* req being initialized */ 588 req->flags = 0; 589 req->error_code = 0; 590 req->orig_req = TW_CL_NULL; 591 req->tw_cli_callback = TW_CL_NULL; 592 593 /* 594 * Look at the status field in the command packet to see how 595 * it completed the last time it was used, and zero out only 596 * the portions that might have changed. Note that we don't 597 * care to zero out the sglist. 598 */ 599 if (req->cmd_pkt->command.cmd_pkt_9k.status) 600 tw_osl_memzero(req->cmd_pkt, 601 sizeof(struct tw_cl_command_header) + 602 28 /* max bytes before sglist */); 603 else 604 tw_osl_memzero(&(req->cmd_pkt->command), 605 28 /* max bytes before sglist */); 606 607 } 608 return(req); 609 } 610 611 612 613 /* 614 * Function name: tw_cli_dbg_printf 615 * Description: Calls OSL print function if dbg_level is appropriate 616 * 617 * Input: dbg_level -- Determines whether or not to print 618 * ctlr_handle -- controller handle 619 * cur_func -- text name of calling function 620 * fmt -- format string for the arguments to follow 621 * ... -- variable number of arguments, to be printed 622 * based on the fmt string 623 * Output: None 624 * Return value: None 625 */ 626 TW_VOID 627 tw_cli_dbg_printf(TW_UINT8 dbg_level, 628 struct tw_cl_ctlr_handle *ctlr_handle, const TW_INT8 *cur_func, 629 TW_INT8 *fmt, ...) 630 { 631 #ifdef TW_OSL_DEBUG 632 TW_INT8 print_str[256]; 633 va_list ap; 634 635 tw_osl_memzero(print_str, 256); 636 if (dbg_level <= TW_OSL_DEBUG_LEVEL_FOR_CL) { 637 tw_osl_sprintf(print_str, "%s: ", cur_func); 638 639 va_start(ap, fmt); 640 tw_osl_vsprintf(print_str + tw_osl_strlen(print_str), fmt, ap); 641 va_end(ap); 642 643 tw_osl_strcpy(print_str + tw_osl_strlen(print_str), "\n"); 644 tw_osl_dbg_printf(ctlr_handle, "%s", print_str); 645 } 646 #endif /* TW_OSL_DEBUG */ 647 } 648 649 650 651 /* 652 * Function name: tw_cli_notify_ctlr_info 653 * Description: Notify OSL of controller info (fw/BIOS versions, etc.). 654 * 655 * Input: ctlr -- ptr to CL internal ctlr context 656 * Output: None 657 * Return value: None 658 */ 659 TW_VOID 660 tw_cli_notify_ctlr_info(struct tw_cli_ctlr_context *ctlr) 661 { 662 TW_INT8 fw_ver[16]; 663 TW_INT8 bios_ver[16]; 664 TW_INT8 ctlr_model[16]; 665 TW_INT32 error[3]; 666 TW_UINT8 num_ports = 0; 667 668 tw_cli_dbg_printf(5, ctlr->ctlr_handle, tw_osl_cur_func(), "entered"); 669 670 /* Get the port count. */ 671 error[0] = tw_cli_get_param(ctlr, TWA_PARAM_CONTROLLER_TABLE, 672 TWA_PARAM_CONTROLLER_PORT_COUNT, &num_ports, 673 1, TW_CL_NULL); 674 675 /* Get the firmware and BIOS versions. */ 676 error[0] = tw_cli_get_param(ctlr, TWA_PARAM_VERSION_TABLE, 677 TWA_PARAM_VERSION_FW, fw_ver, 16, TW_CL_NULL); 678 error[1] = tw_cli_get_param(ctlr, TWA_PARAM_VERSION_TABLE, 679 TWA_PARAM_VERSION_BIOS, bios_ver, 16, TW_CL_NULL); 680 error[2] = tw_cli_get_param(ctlr, TWA_PARAM_VERSION_TABLE, 681 TWA_PARAM_CTLR_MODEL, ctlr_model, 16, TW_CL_NULL); 682 683 tw_cl_create_event(ctlr->ctlr_handle, TW_CL_FALSE, 684 TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR, 685 0x1300, 0x3, TW_CL_SEVERITY_INFO_STRING, 686 "Controller details", 687 "Model %.16s, %d ports, Firmware %.16s, BIOS %.16s", 688 error[2]?(TW_INT8 *)TW_CL_NULL:ctlr_model, 689 num_ports, 690 error[0]?(TW_INT8 *)TW_CL_NULL:fw_ver, 691 error[1]?(TW_INT8 *)TW_CL_NULL:bios_ver); 692 } 693 694 695 696 /* 697 * Function name: tw_cli_check_ctlr_state 698 * Description: Makes sure that the fw status register reports a 699 * proper status. 700 * 701 * Input: ctlr -- ptr to CL internal ctlr context 702 * status_reg-- value in the status register 703 * Output: None 704 * Return value: 0 -- no errors 705 * non-zero-- errors 706 */ 707 TW_INT32 708 tw_cli_check_ctlr_state(struct tw_cli_ctlr_context *ctlr, TW_UINT32 status_reg) 709 { 710 struct tw_cl_ctlr_handle *ctlr_handle = ctlr->ctlr_handle; 711 TW_INT32 error = TW_OSL_ESUCCESS; 712 713 tw_cli_dbg_printf(8, ctlr->ctlr_handle, tw_osl_cur_func(), "entered"); 714 715 /* Check if the 'micro-controller ready' bit is not set. */ 716 if (!(status_reg & TWA_STATUS_MICROCONTROLLER_READY)) { 717 TW_INT8 desc[200]; 718 719 tw_osl_memzero(desc, 200); 720 if (!(ctlr->reset_phase1_in_progress)) { 721 tw_cl_create_event(ctlr_handle, TW_CL_FALSE, 722 TW_CL_MESSAGE_SOURCE_COMMON_LAYER_EVENT, 723 0x1301, 0x1, TW_CL_SEVERITY_ERROR_STRING, 724 "Missing expected status bit(s)", 725 "status reg = 0x%x; Missing bits: %s", 726 status_reg, 727 tw_cli_describe_bits( 728 TWA_STATUS_MICROCONTROLLER_READY, 729 desc)); 730 error = TW_OSL_EGENFAILURE; 731 } 732 } 733 734 /* Check if any error bits are set. */ 735 if ((status_reg & TWA_STATUS_UNEXPECTED_BITS) != 0) { 736 TW_INT8 desc[200]; 737 738 tw_osl_memzero(desc, 200); 739 740 /* Skip queue error msgs during 9650SE/9690SA reset */ 741 if (((ctlr->device_id != TW_CL_DEVICE_ID_9K_E) && 742 (ctlr->device_id != TW_CL_DEVICE_ID_9K_SA)) || 743 (!(ctlr->reset_in_progress)) || 744 ((status_reg & TWA_STATUS_QUEUE_ERROR_INTERRUPT) == 0)) 745 { 746 tw_cl_create_event(ctlr_handle, TW_CL_FALSE, 747 TW_CL_MESSAGE_SOURCE_COMMON_LAYER_EVENT, 748 0x1302, 0x1, TW_CL_SEVERITY_ERROR_STRING, 749 "Unexpected status bit(s)", 750 "status reg = 0x%x Unexpected bits: %s", 751 status_reg & TWA_STATUS_UNEXPECTED_BITS, 752 tw_cli_describe_bits(status_reg & 753 TWA_STATUS_UNEXPECTED_BITS, desc)); 754 } 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 */ 825 TW_INT8 * 826 tw_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 */ 869 TW_VOID 870 tw_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 */ 914 TW_VOID 915 tw_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 */ 937 TW_VOID 938 tw_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