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