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