tw_cl_misc.c revision 144966
1272343Sngie/* 2272343Sngie * Copyright (c) 2004-05 Applied Micro Circuits Corporation. 3272343Sngie * Copyright (c) 2004-05 Vinod Kashyap 4272343Sngie * All rights reserved. 5272343Sngie * 6272343Sngie * Redistribution and use in source and binary forms, with or without 7272343Sngie * modification, are permitted provided that the following conditions 8272343Sngie * are met: 9272343Sngie * 1. Redistributions of source code must retain the above copyright 10272343Sngie * notice, this list of conditions and the following disclaimer. 11272343Sngie * 2. Redistributions in binary form must reproduce the above copyright 12272343Sngie * notice, this list of conditions and the following disclaimer in the 13272343Sngie * documentation and/or other materials provided with the distribution. 14272343Sngie * 15272343Sngie * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16272343Sngie * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17272343Sngie * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18272343Sngie * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19272343Sngie * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20272343Sngie * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21272343Sngie * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22272343Sngie * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23272343Sngie * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24272343Sngie * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25272343Sngie * SUCH DAMAGE. 26272343Sngie * 27272343Sngie * $FreeBSD: head/sys/dev/twa/tw_cl_misc.c 144966 2005-04-12 22:07:11Z vkashyap $ 28272343Sngie */ 29272343Sngie 30272343Sngie/* 31272343Sngie * AMCC'S 3ware driver for 9000 series storage controllers. 32272343Sngie * 33272343Sngie * Author: Vinod Kashyap 34272343Sngie */ 35272343Sngie 36272343Sngie 37272343Sngie/* 38272343Sngie * Common Layer miscellaneous functions. 39272343Sngie */ 40272343Sngie 41272343Sngie 42272343Sngie#include "tw_osl_share.h" 43272343Sngie#include "tw_cl_share.h" 44272343Sngie#include "tw_cl_fwif.h" 45272343Sngie#include "tw_cl_ioctl.h" 46272343Sngie#include "tw_cl.h" 47272343Sngie#include "tw_cl_externs.h" 48272343Sngie#include "tw_osl_ioctl.h" 49272343Sngie 50272343Sngie 51272343Sngie 52272343Sngie/* AEN severity table. */ 53272343SngieTW_INT8 *tw_cli_severity_string_table[] = { 54272343Sngie "None", 55272343Sngie TW_CL_SEVERITY_ERROR_STRING, 56272343Sngie TW_CL_SEVERITY_WARNING_STRING, 57272343Sngie TW_CL_SEVERITY_INFO_STRING, 58272343Sngie TW_CL_SEVERITY_DEBUG_STRING, 59272343Sngie "" 60272343Sngie}; 61272343Sngie 62272343Sngie 63272343Sngie 64272343Sngie/* 65272343Sngie * Function name: tw_cli_drain_complete_queue 66272343Sngie * Description: This function gets called during a controller reset. 67272343Sngie * It errors back to CAM, all those requests that are 68272343Sngie * in the complete queue, at the time of the reset. Any 69272343Sngie * CL internal requests will be simply freed. 70272343Sngie * 71272343Sngie * Input: ctlr -- ptr to CL internal ctlr context 72272343Sngie * Output: None 73272343Sngie * Return value: None 74272343Sngie */ 75272343SngieTW_VOID 76272343Sngietw_cli_drain_complete_queue(struct tw_cli_ctlr_context *ctlr) 77272343Sngie{ 78272343Sngie struct tw_cli_req_context *req; 79272343Sngie struct tw_cl_req_packet *req_pkt; 80272343Sngie 81272343Sngie tw_cli_dbg_printf(3, ctlr->ctlr_handle, tw_osl_cur_func(), "entered"); 82272343Sngie 83272343Sngie /* Walk the busy queue. */ 84272343Sngie while ((req = tw_cli_req_q_remove_head(ctlr, TW_CLI_COMPLETE_Q))) { 85272343Sngie if (req->flags & TW_CLI_REQ_FLAGS_INTERNAL) { 86272343Sngie /* 87272343Sngie * It's an internal request. Set the appropriate 88272343Sngie * error and call the CL internal callback if there's 89272343Sngie * one. If the request originator is polling for 90272343Sngie * completion, he should be checking req->error to 91272343Sngie * determine that the request did not go through. 92272343Sngie * The request originators are responsible for the 93272343Sngie * clean-up. 94272343Sngie */ 95272343Sngie req->error_code = TW_CL_ERR_REQ_BUS_RESET; 96272343Sngie if (req->tw_cli_callback) 97272343Sngie req->tw_cli_callback(req); 98272343Sngie } else { 99272343Sngie 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 CAM, all those requests that were 120 * pending with the firmware, at the time of the reset. 121 * 122 * Input: ctlr -- ptr to CL internal ctlr context 123 * Output: None 124 * Return value: None 125 */ 126TW_VOID 127tw_cli_drain_busy_queue(struct tw_cli_ctlr_context *ctlr) 128{ 129 struct tw_cli_req_context *req; 130 struct tw_cl_req_packet *req_pkt; 131 132 tw_cli_dbg_printf(3, ctlr->ctlr_handle, tw_osl_cur_func(), "entered"); 133 134 /* Walk the busy queue. */ 135 while ((req = tw_cli_req_q_remove_head(ctlr, TW_CLI_BUSY_Q))) { 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 { 150 if ((req_pkt = req->orig_req)) { 151 /* It's a SCSI request. Complete it. */ 152 tw_cli_dbg_printf(2, ctlr->ctlr_handle, 153 tw_osl_cur_func(), 154 "Completing busy request %p on reset", 155 req); 156 req_pkt->status = TW_CL_ERR_REQ_BUS_RESET; 157 req_pkt->tw_osl_callback(req->req_handle); 158 } 159 tw_cli_req_q_insert_tail(req, TW_CLI_FREE_Q); 160 } 161 } 162} 163 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 CAM, all those requests that were 170 * 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 177TW_VOID 178tw_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 if (req->flags & TW_CLI_REQ_FLAGS_INTERNAL) { 190 /* 191 * It's an internal request. Set the appropriate 192 * error and call the CL internal callback if there's 193 * one. If the request originator is polling for 194 * completion, he should be checking req->error to 195 * determine that the request did not go through. 196 * The request originators are responsible for the 197 * clean-up. 198 */ 199 req->error_code = TW_CL_ERR_REQ_BUS_RESET; 200 if (req->tw_cli_callback) 201 req->tw_cli_callback(req); 202 } else { 203 if ((req_pkt = req->orig_req)) { 204 /* It's an external request. Complete it. */ 205 tw_cli_dbg_printf(2, ctlr->ctlr_handle, 206 tw_osl_cur_func(), 207 "Completing pending request %p " 208 "on reset", req); 209 req_pkt->status = TW_CL_ERR_REQ_BUS_RESET; 210 req_pkt->tw_osl_callback(req->req_handle); 211 } 212 tw_cli_req_q_insert_tail(req, TW_CLI_FREE_Q); 213 } 214 } 215} 216 217 218 219/* 220 * Function name: tw_cli_drain_response_queue 221 * Description: Drain the controller response queue. 222 * 223 * Input: ctlr -- ptr to per ctlr structure 224 * Output: None 225 * Return value: 0 -- success 226 * non-zero-- failure 227 */ 228TW_INT32 229tw_cli_drain_response_queue(struct tw_cli_ctlr_context *ctlr) 230{ 231 TW_UINT32 resp; 232 TW_UINT32 status_reg; 233 234 tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(), "entered"); 235 236 for (;;) { 237 status_reg = TW_CLI_READ_STATUS_REGISTER(ctlr->ctlr_handle); 238 239 if (tw_cli_check_ctlr_state(ctlr, status_reg)) 240 return(TW_OSL_EGENFAILURE); 241 242 if (status_reg & TWA_STATUS_RESPONSE_QUEUE_EMPTY) 243 return(TW_OSL_ESUCCESS); /* no more response queue entries */ 244 245 resp = TW_CLI_READ_RESPONSE_QUEUE(ctlr->ctlr_handle); 246 } 247} 248 249 250 251/* 252 * Function name: tw_cli_drain_aen_queue 253 * Description: Fetches all un-retrieved AEN's posted by fw. 254 * 255 * Input: ctlr -- ptr to CL internal ctlr context 256 * Output: None 257 * Return value: 0 -- success 258 * non-zero-- failure 259 */ 260TW_INT32 261tw_cli_drain_aen_queue(struct tw_cli_ctlr_context *ctlr) 262{ 263 struct tw_cli_req_context *req; 264 struct tw_cl_command_header *cmd_hdr; 265 TW_TIME end_time; 266 TW_UINT16 aen_code; 267 TW_INT32 error; 268 269 tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(), "entered"); 270 271 for (;;) { 272 if ((req = tw_cli_get_request(ctlr 273#ifdef TW_OSL_NON_DMA_MEM_ALLOC_PER_REQUEST 274 , TW_CL_NULL 275#endif /* TW_OSL_NON_DMA_MEM_ALLOC_PER_REQUEST */ 276 )) == TW_CL_NULL) { 277 error = TW_OSL_EBUSY; 278 break; 279 } 280 281#ifdef TW_OSL_DMA_MEM_ALLOC_PER_REQUEST 282 283 req->cmd_pkt = ctlr->cmd_pkt_buf; 284 req->cmd_pkt_phys = ctlr->cmd_pkt_phys; 285 tw_osl_memzero(req->cmd_pkt, 286 sizeof(struct tw_cl_command_header) + 287 28 /* max bytes before sglist */); 288 289#endif /* TW_OSL_DMA_MEM_ALLOC_PER_REQUEST */ 290 291 req->flags |= TW_CLI_REQ_FLAGS_INTERNAL; 292 req->tw_cli_callback = TW_CL_NULL; 293 if ((error = tw_cli_send_scsi_cmd(req, 294 0x03 /* REQUEST_SENSE */))) { 295 tw_cli_dbg_printf(1, ctlr->ctlr_handle, 296 tw_osl_cur_func(), 297 "Cannot send command to fetch aen"); 298 break; 299 } 300 301 end_time = tw_osl_get_local_time() + 302 TW_CLI_REQUEST_TIMEOUT_PERIOD; 303 do { 304 if ((error = req->error_code)) 305 /* 306 * This will take care of completion due to 307 * a reset, or a failure in 308 * tw_cli_submit_pending_queue. 309 */ 310 goto out; 311 312 tw_cli_process_resp_intr(req->ctlr); 313 314 if ((req->state != TW_CLI_REQ_STATE_BUSY) && 315 (req->state != TW_CLI_REQ_STATE_PENDING)) 316 break; 317 } while (tw_osl_get_local_time() <= end_time); 318 319 if (req->state != TW_CLI_REQ_STATE_COMPLETE) { 320 error = TW_OSL_ETIMEDOUT; 321 break; 322 } 323 324 if ((error = req->cmd_pkt->command.cmd_pkt_9k.status)) { 325 cmd_hdr = &req->cmd_pkt->cmd_hdr; 326 tw_cli_create_ctlr_event(ctlr, 327 TW_CL_MESSAGE_SOURCE_CONTROLLER_ERROR, 328 cmd_hdr); 329 break; 330 } 331 332 aen_code = tw_cli_manage_aen(ctlr, req); 333 if (aen_code == TWA_AEN_QUEUE_EMPTY) 334 break; 335 if (aen_code == TWA_AEN_SYNC_TIME_WITH_HOST) 336 continue; 337 338 ctlr->state &= ~TW_CLI_CTLR_STATE_INTERNAL_REQ_BUSY; 339 tw_cli_req_q_insert_tail(req, TW_CLI_FREE_Q); 340 } 341 342out: 343 if (req) { 344 if (req->data) 345 ctlr->state &= ~TW_CLI_CTLR_STATE_INTERNAL_REQ_BUSY; 346 tw_cli_req_q_insert_tail(req, TW_CLI_FREE_Q); 347 } 348 return(error); 349} 350 351 352 353/* 354 * Function name: tw_cli_find_aen 355 * Description: Reports whether a given AEN ever occurred. 356 * 357 * Input: ctlr -- ptr to CL internal ctlr context 358 * aen_code-- AEN to look for 359 * Output: None 360 * Return value: 0 -- success 361 * non-zero-- failure 362 */ 363TW_INT32 364tw_cli_find_aen(struct tw_cli_ctlr_context *ctlr, TW_UINT16 aen_code) 365{ 366 TW_UINT32 last_index; 367 TW_INT32 i; 368 369 tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(), "entered"); 370 371 if (ctlr->aen_q_wrapped) 372 last_index = ctlr->aen_head; 373 else 374 last_index = 0; 375 376 i = ctlr->aen_head; 377 do { 378 i = (i + ctlr->max_aens_supported - 1) % 379 ctlr->max_aens_supported; 380 if (ctlr->aen_queue[i].aen_code == aen_code) 381 return(TW_OSL_ESUCCESS); 382 } while (i != last_index); 383 384 return(TW_OSL_EGENFAILURE); 385} 386 387 388 389/* 390 * Function name: tw_cli_poll_status 391 * Description: Poll for a given status to show up in the firmware 392 * status register. 393 * 394 * Input: ctlr -- ptr to CL internal ctlr context 395 * status -- status to look for 396 * timeout -- max # of seconds to wait before giving up 397 * Output: None 398 * Return value: 0 -- success 399 * non-zero-- failure 400 */ 401TW_INT32 402tw_cli_poll_status(struct tw_cli_ctlr_context *ctlr, TW_UINT32 status, 403 TW_UINT32 timeout) 404{ 405 TW_TIME end_time; 406 TW_UINT32 status_reg; 407 408 tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(), "entered"); 409 410 end_time = tw_osl_get_local_time() + timeout; 411 do { 412 status_reg = TW_CLI_READ_STATUS_REGISTER(ctlr->ctlr_handle); 413 if ((status_reg & status) == status) 414 /* got the required bit(s) */ 415 return(TW_OSL_ESUCCESS); 416 417 /* 418 * The OSL should not define TW_OSL_CAN_SLEEP if it calls 419 * tw_cl_deferred_interrupt from within the ISR and not a 420 * lower interrupt level, since, in that case, we might end 421 * up here, and try to sleep (within an ISR). 422 */ 423#ifndef TW_OSL_CAN_SLEEP 424 /* OSL doesn't support sleeping; will spin. */ 425 tw_osl_delay(1000); 426#else /* TW_OSL_CAN_SLEEP */ 427#if 0 428 /* Will spin if initializing, sleep otherwise. */ 429 if (!(ctlr->state & TW_CLI_CTLR_STATE_ACTIVE)) 430 tw_osl_delay(1000); 431 else 432 tw_osl_sleep(ctlr->ctlr_handle, 433 &(ctlr->sleep_handle), 1 /* ms */); 434#else /* #if 0 */ 435 /* 436 * Will always spin for now (since reset holds a spin lock). 437 * We could free io_lock after the call to TW_CLI_SOFT_RESET, 438 * so we could sleep here. To block new requests (since 439 * the lock will have been released) we could use the 440 * ...RESET_IN_PROGRESS flag. Need to revisit. 441 */ 442 tw_osl_delay(1000); 443#endif /* #if 0 */ 444#endif /* TW_OSL_CAN_SLEEP */ 445 } while (tw_osl_get_local_time() <= end_time); 446 447 return(TW_OSL_ETIMEDOUT); 448} 449 450 451 452/* 453 * Function name: tw_cl_create_event 454 * Description: Creates and queues ctlr/CL/OSL AEN's to be 455 * supplied to user-space tools on request. 456 * Also notifies OS Layer. 457 * Input: ctlr -- ptr to CL internal ctlr context 458 * queue_event-- TW_CL_TRUE --> queue event; 459 * TW_CL_FALSE--> don't queue event 460 * (simply notify OSL) 461 * event_src -- source of event 462 * event_code -- AEN/error code 463 * severity -- severity of event 464 * severity_str--Text description of severity 465 * event_desc -- standard string related to the event/error 466 * event_specific_desc -- format string for additional 467 * info about the event 468 * ... -- additional arguments conforming to the format 469 * specified by event_specific_desc 470 * Output: None 471 * Return value: None 472 */ 473TW_VOID 474tw_cl_create_event(struct tw_cl_ctlr_handle *ctlr_handle, 475 TW_UINT8 queue_event, TW_UINT8 event_src, TW_UINT16 event_code, 476 TW_UINT8 severity, TW_UINT8 *severity_str, TW_UINT8 *event_desc, 477 TW_UINT8 *event_specific_desc, ...) 478{ 479 struct tw_cli_ctlr_context *ctlr = ctlr_handle->cl_ctlr_ctxt; 480 struct tw_cl_event_packet event_pkt; 481 struct tw_cl_event_packet *event; 482 va_list ap; 483 484 tw_cli_dbg_printf(8, ctlr_handle, tw_osl_cur_func(), "entered"); 485 486 if ((ctlr) && (queue_event)) { 487 /* Protect access to ctlr->aen_head. */ 488 tw_osl_get_lock(ctlr_handle, ctlr->gen_lock); 489 490 /* Queue the event. */ 491 event = &(ctlr->aen_queue[ctlr->aen_head]); 492 tw_osl_memzero(event->parameter_data, 493 sizeof(event->parameter_data)); 494 495 if (event->retrieved == TW_CL_AEN_NOT_RETRIEVED) 496 ctlr->aen_q_overflow = TW_CL_TRUE; 497 event->sequence_id = ++(ctlr->aen_cur_seq_id); 498 if ((ctlr->aen_head + 1) == ctlr->max_aens_supported) { 499 tw_cli_dbg_printf(4, ctlr->ctlr_handle, 500 tw_osl_cur_func(), "AEN queue wrapped"); 501 ctlr->aen_q_wrapped = TW_CL_TRUE; 502 } 503 } else { 504 event = &event_pkt; 505 tw_osl_memzero(event, sizeof(struct tw_cl_event_packet)); 506 } 507 508 event->event_src = event_src; 509 event->time_stamp_sec = (TW_UINT32)tw_osl_get_local_time(); 510 event->aen_code = event_code; 511 event->severity = severity; 512 tw_osl_strcpy(event->severity_str, severity_str); 513 event->retrieved = TW_CL_AEN_NOT_RETRIEVED; 514 515 va_start(ap, event_specific_desc); 516 tw_osl_vsprintf(event->parameter_data, event_specific_desc, ap); 517 va_end(ap); 518 519 event->parameter_len = 520 (TW_UINT8)(tw_osl_strlen(event->parameter_data)); 521 tw_osl_strcpy(event->parameter_data + event->parameter_len + 1, 522 event_desc); 523 event->parameter_len += (1 + tw_osl_strlen(event_desc)); 524 525 tw_cli_dbg_printf(4, ctlr_handle, tw_osl_cur_func(), 526 "event = %x %x %x %x %x %x %x\n %s", 527 event->sequence_id, 528 event->time_stamp_sec, 529 event->aen_code, 530 event->severity, 531 event->retrieved, 532 event->repeat_count, 533 event->parameter_len, 534 event->parameter_data); 535 536 if ((ctlr) && (queue_event)) { 537 ctlr->aen_head = 538 (ctlr->aen_head + 1) % ctlr->max_aens_supported; 539 /* Free access to ctlr->aen_head. */ 540 tw_osl_free_lock(ctlr_handle, ctlr->gen_lock); 541 } 542 tw_osl_notify_event(ctlr_handle, event); 543} 544 545 546 547/* 548 * Function name: tw_cli_get_request 549 * Description: Gets a request pkt from the free queue. 550 * 551 * Input: ctlr -- ptr to CL internal ctlr context 552 * req_pkt -- ptr to OSL built req_pkt, if there's one 553 * Output: None 554 * Return value: ptr to request pkt -- success 555 * TW_CL_NULL -- failure 556 */ 557struct tw_cli_req_context * 558tw_cli_get_request(struct tw_cli_ctlr_context *ctlr 559#ifdef TW_OSL_NON_DMA_MEM_ALLOC_PER_REQUEST 560 , struct tw_cl_req_packet *req_pkt 561#endif /* TW_OSL_NON_DMA_MEM_ALLOC_PER_REQUEST */ 562 ) 563{ 564 struct tw_cli_req_context *req; 565 566 tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(), "entered"); 567 568#ifdef TW_OSL_NON_DMA_MEM_ALLOC_PER_REQUEST 569 570 if (req_pkt) { 571 if (ctlr->num_free_req_ids == 0) { 572 DbgPrint("Out of req_ids!!\n"); 573 return(TW_CL_NULL); 574 } 575 ctlr->num_free_req_ids--; 576 req = (struct tw_cli_req_context *)(req_pkt->non_dma_mem); 577 req->ctlr = ctlr; 578 req->request_id = ctlr->free_req_ids[ctlr->free_req_head]; 579 ctlr->busy_reqs[req->request_id] = req; 580 ctlr->free_req_head = (ctlr->free_req_head + 1) % 581 (ctlr->max_simult_reqs - 1); 582 } else 583 584#endif /* TW_OSL_NON_DMA_MEM_ALLOC_PER_REQUEST */ 585 { 586 /* Get a free request packet. */ 587 req = tw_cli_req_q_remove_head(ctlr, TW_CLI_FREE_Q); 588 } 589 590 /* Initialize some fields to their defaults. */ 591 if (req) { 592 req->req_handle = TW_CL_NULL; 593 req->data = TW_CL_NULL; 594 req->length = 0; 595 req->data_phys = 0; 596 req->state = TW_CLI_REQ_STATE_INIT; /* req being initialized */ 597 req->flags = 0; 598 req->error_code = 0; 599 req->orig_req = TW_CL_NULL; 600 req->tw_cli_callback = TW_CL_NULL; 601 602#ifndef TW_OSL_DMA_MEM_ALLOC_PER_REQUEST 603 604 /* 605 * Look at the status field in the command packet to see how 606 * it completed the last time it was used, and zero out only 607 * the portions that might have changed. Note that we don't 608 * care to zero out the sglist. 609 */ 610 if (req->cmd_pkt->command.cmd_pkt_9k.status) 611 tw_osl_memzero(req->cmd_pkt, 612 sizeof(struct tw_cl_command_header) + 613 28 /* max bytes before sglist */); 614 else 615 tw_osl_memzero(&(req->cmd_pkt->command), 616 28 /* max bytes before sglist */); 617 618#endif /* TW_OSL_DMA_MEM_ALLOC_PER_REQUEST */ 619 } 620 return(req); 621} 622 623 624 625/* 626 * Function name: tw_cli_dbg_printf 627 * Description: Calls OSL print function if dbg_level is appropriate 628 * 629 * Input: dbg_level -- Determines whether or not to print 630 * ctlr_handle -- controller handle 631 * cur_func -- text name of calling function 632 * fmt -- format string for the arguments to follow 633 * ... -- variable number of arguments, to be printed 634 * based on the fmt string 635 * Output: None 636 * Return value: None 637 */ 638TW_VOID 639tw_cli_dbg_printf(TW_UINT8 dbg_level, 640 struct tw_cl_ctlr_handle *ctlr_handle, const TW_INT8 *cur_func, 641 TW_INT8 *fmt, ...) 642{ 643#ifdef TW_OSL_DEBUG 644 TW_INT8 print_str[256]; 645 va_list ap; 646 647 tw_osl_memzero(print_str, 256); 648 if (dbg_level <= TW_OSL_DEBUG_LEVEL_FOR_CL) { 649 tw_osl_sprintf(print_str, "%s: ", cur_func); 650 651 va_start(ap, fmt); 652 tw_osl_vsprintf(print_str + tw_osl_strlen(print_str), fmt, ap); 653 va_end(ap); 654 655 tw_osl_strcpy(print_str + tw_osl_strlen(print_str), "\n"); 656 tw_osl_dbg_printf(ctlr_handle, print_str); 657 } 658#endif /* TW_OSL_DEBUG */ 659} 660 661 662 663/* 664 * Function name: tw_cli_notify_ctlr_info 665 * Description: Notify OSL of controller info (fw/BIOS versions, etc.). 666 * 667 * Input: ctlr -- ptr to CL internal ctlr context 668 * Output: None 669 * Return value: None 670 */ 671TW_VOID 672tw_cli_notify_ctlr_info(struct tw_cli_ctlr_context *ctlr) 673{ 674 TW_INT8 fw_ver[16]; 675 TW_INT8 bios_ver[16]; 676 TW_INT32 error[2]; 677 TW_UINT8 num_ports = 0; 678 679 tw_cli_dbg_printf(5, ctlr->ctlr_handle, tw_osl_cur_func(), "entered"); 680 681 /* Get the port count. */ 682 error[0] = tw_cli_get_param(ctlr, TWA_PARAM_CONTROLLER_TABLE, 683 TWA_PARAM_CONTROLLER_PORT_COUNT, &num_ports, 684 1, TW_CL_NULL); 685 686 /* Get the firmware and BIOS versions. */ 687 error[0] = tw_cli_get_param(ctlr, TWA_PARAM_VERSION_TABLE, 688 TWA_PARAM_VERSION_FW, fw_ver, 16, TW_CL_NULL); 689 error[1] = tw_cli_get_param(ctlr, TWA_PARAM_VERSION_TABLE, 690 TWA_PARAM_VERSION_BIOS, bios_ver, 16, TW_CL_NULL); 691 692 tw_cl_create_event(ctlr->ctlr_handle, TW_CL_FALSE, 693 TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR, 694 0x1300, 0x3, TW_CL_SEVERITY_INFO_STRING, 695 "Controller details:", 696 "%d ports, Firmware %.16s, BIOS %.16s", 697 num_ports, 698 error[0]?(TW_INT8 *)TW_CL_NULL:fw_ver, 699 error[1]?(TW_INT8 *)TW_CL_NULL:bios_ver); 700} 701 702 703 704/* 705 * Function name: tw_cli_check_ctlr_state 706 * Description: Makes sure that the fw status register reports a 707 * proper status. 708 * 709 * Input: ctlr -- ptr to CL internal ctlr context 710 * status_reg-- value in the status register 711 * Output: None 712 * Return value: 0 -- no errors 713 * non-zero-- errors 714 */ 715TW_INT32 716tw_cli_check_ctlr_state(struct tw_cli_ctlr_context *ctlr, TW_UINT32 status_reg) 717{ 718 struct tw_cl_ctlr_handle *ctlr_handle = ctlr->ctlr_handle; 719 TW_INT32 error = TW_OSL_ESUCCESS; 720 721 tw_cli_dbg_printf(8, ctlr->ctlr_handle, tw_osl_cur_func(), "entered"); 722 723 /* Check if the 'micro-controller ready' bit is not set. */ 724 if ((status_reg & TWA_STATUS_EXPECTED_BITS) != 725 TWA_STATUS_EXPECTED_BITS) { 726 TW_INT8 desc[200]; 727 728 tw_osl_memzero(desc, 200); 729 tw_cl_create_event(ctlr_handle, TW_CL_TRUE, 730 TW_CL_MESSAGE_SOURCE_COMMON_LAYER_EVENT, 731 0x1301, 0x1, TW_CL_SEVERITY_ERROR_STRING, 732 "Missing expected status bit(s)", 733 "status reg = 0x%x; Missing bits: %s", 734 status_reg, 735 tw_cli_describe_bits (~status_reg & 736 TWA_STATUS_EXPECTED_BITS, desc)); 737 error = TW_OSL_EGENFAILURE; 738 } 739 740 /* Check if any error bits are set. */ 741 if ((status_reg & TWA_STATUS_UNEXPECTED_BITS) != 0) { 742 TW_INT8 desc[200]; 743 744 tw_osl_memzero(desc, 200); 745 tw_cl_create_event(ctlr_handle, TW_CL_TRUE, 746 TW_CL_MESSAGE_SOURCE_COMMON_LAYER_EVENT, 747 0x1302, 0x1, TW_CL_SEVERITY_ERROR_STRING, 748 "Unexpected status bit(s)", 749 "status reg = 0x%x Unexpected bits: %s", 750 status_reg & TWA_STATUS_UNEXPECTED_BITS, 751 tw_cli_describe_bits(status_reg & 752 TWA_STATUS_UNEXPECTED_BITS, desc)); 753 754 if (status_reg & TWA_STATUS_PCI_PARITY_ERROR_INTERRUPT) { 755 tw_cl_create_event(ctlr_handle, TW_CL_TRUE, 756 TW_CL_MESSAGE_SOURCE_COMMON_LAYER_EVENT, 757 0x1303, 0x1, TW_CL_SEVERITY_ERROR_STRING, 758 "PCI parity error: clearing... " 759 "Re-seat/move/replace card", 760 "status reg = 0x%x %s", 761 status_reg, 762 tw_cli_describe_bits(status_reg, desc)); 763 TW_CLI_WRITE_CONTROL_REGISTER(ctlr->ctlr_handle, 764 TWA_CONTROL_CLEAR_PARITY_ERROR); 765 766#ifdef TW_OSL_PCI_CONFIG_ACCESSIBLE 767 tw_osl_write_pci_config(ctlr->ctlr_handle, 768 TW_CLI_PCI_CONFIG_STATUS_OFFSET, 769 TWA_PCI_CONFIG_CLEAR_PARITY_ERROR, 2); 770#endif /* TW_OSL_PCI_CONFIG_ACCESSIBLE */ 771 772 } 773 774 if (status_reg & TWA_STATUS_PCI_ABORT_INTERRUPT) { 775 tw_cl_create_event(ctlr_handle, TW_CL_TRUE, 776 TW_CL_MESSAGE_SOURCE_COMMON_LAYER_EVENT, 777 0x1304, 0x1, TW_CL_SEVERITY_ERROR_STRING, 778 "PCI abort: clearing... ", 779 "status reg = 0x%x %s", 780 status_reg, 781 tw_cli_describe_bits(status_reg, desc)); 782 TW_CLI_WRITE_CONTROL_REGISTER(ctlr->ctlr_handle, 783 TWA_CONTROL_CLEAR_PCI_ABORT); 784 785#ifdef TW_OSL_PCI_CONFIG_ACCESSIBLE 786 tw_osl_write_pci_config(ctlr->ctlr_handle, 787 TW_CLI_PCI_CONFIG_STATUS_OFFSET, 788 TWA_PCI_CONFIG_CLEAR_PCI_ABORT, 2); 789#endif /* TW_OSL_PCI_CONFIG_ACCESSIBLE */ 790 791 } 792 793 if (status_reg & TWA_STATUS_QUEUE_ERROR_INTERRUPT) { 794 tw_cl_create_event(ctlr_handle, TW_CL_TRUE, 795 TW_CL_MESSAGE_SOURCE_COMMON_LAYER_EVENT, 796 0x1305, 0x1, TW_CL_SEVERITY_ERROR_STRING, 797 "Controller queue error: clearing... ", 798 "status reg = 0x%x %s", 799 status_reg, 800 tw_cli_describe_bits(status_reg, desc)); 801 TW_CLI_WRITE_CONTROL_REGISTER(ctlr->ctlr_handle, 802 TWA_CONTROL_CLEAR_QUEUE_ERROR); 803 } 804 805 if (status_reg & TWA_STATUS_SBUF_WRITE_ERROR) { 806 tw_cl_create_event(ctlr_handle, TW_CL_TRUE, 807 TW_CL_MESSAGE_SOURCE_COMMON_LAYER_EVENT, 808 0x1306, 0x1, TW_CL_SEVERITY_ERROR_STRING, 809 "SBUF write error: clearing... ", 810 "status reg = 0x%x %s", 811 status_reg, 812 tw_cli_describe_bits(status_reg, desc)); 813 TW_CLI_WRITE_CONTROL_REGISTER(ctlr->ctlr_handle, 814 TWA_CONTROL_CLEAR_SBUF_WRITE_ERROR); 815 } 816 817 if (status_reg & TWA_STATUS_MICROCONTROLLER_ERROR) { 818 tw_cl_create_event(ctlr_handle, TW_CL_TRUE, 819 TW_CL_MESSAGE_SOURCE_COMMON_LAYER_EVENT, 820 0x1307, 0x1, TW_CL_SEVERITY_ERROR_STRING, 821 "Micro-controller error! ", 822 "status reg = 0x%x %s", 823 status_reg, 824 tw_cli_describe_bits(status_reg, desc)); 825 error = TW_OSL_EGENFAILURE; 826 } 827 } 828 return(error); 829} 830 831 832 833/* 834 * Function name: tw_cli_describe_bits 835 * Description: Given the value of the status register, returns a 836 * string describing the meaning of each set bit. 837 * 838 * Input: reg -- status register value 839 * Output: Pointer to a string describing each set bit 840 * Return value: Pointer to the string describing each set bit 841 */ 842TW_INT8 * 843tw_cli_describe_bits(TW_UINT32 reg, TW_INT8 *str) 844{ 845 tw_osl_strcpy(str, "["); 846 847 if (reg & TWA_STATUS_SBUF_WRITE_ERROR) 848 tw_osl_strcpy(str, "SBUF_WR_ERR,"); 849 if (reg & TWA_STATUS_COMMAND_QUEUE_EMPTY) 850 tw_osl_strcpy(&str[tw_osl_strlen(str)], "CMD_Q_EMPTY,"); 851 if (reg & TWA_STATUS_MICROCONTROLLER_READY) 852 tw_osl_strcpy(&str[tw_osl_strlen(str)], "MC_RDY,"); 853 if (reg & TWA_STATUS_RESPONSE_QUEUE_EMPTY) 854 tw_osl_strcpy(&str[tw_osl_strlen(str)], "RESP_Q_EMPTY,"); 855 if (reg & TWA_STATUS_COMMAND_QUEUE_FULL) 856 tw_osl_strcpy(&str[tw_osl_strlen(str)], "CMD_Q_FULL,"); 857 if (reg & TWA_STATUS_RESPONSE_INTERRUPT) 858 tw_osl_strcpy(&str[tw_osl_strlen(str)], "RESP_INTR,"); 859 if (reg & TWA_STATUS_COMMAND_INTERRUPT) 860 tw_osl_strcpy(&str[tw_osl_strlen(str)], "CMD_INTR,"); 861 if (reg & TWA_STATUS_ATTENTION_INTERRUPT) 862 tw_osl_strcpy(&str[tw_osl_strlen(str)], "ATTN_INTR,"); 863 if (reg & TWA_STATUS_HOST_INTERRUPT) 864 tw_osl_strcpy(&str[tw_osl_strlen(str)], "HOST_INTR,"); 865 if (reg & TWA_STATUS_PCI_ABORT_INTERRUPT) 866 tw_osl_strcpy(&str[tw_osl_strlen(str)], "PCI_ABRT,"); 867 if (reg & TWA_STATUS_MICROCONTROLLER_ERROR) 868 tw_osl_strcpy(&str[tw_osl_strlen(str)], "MC_ERR,"); 869 if (reg & TWA_STATUS_QUEUE_ERROR_INTERRUPT) 870 tw_osl_strcpy(&str[tw_osl_strlen(str)], "Q_ERR,"); 871 if (reg & TWA_STATUS_PCI_PARITY_ERROR_INTERRUPT) 872 tw_osl_strcpy(&str[tw_osl_strlen(str)], "PCI_PERR"); 873 874 tw_osl_strcpy(&str[tw_osl_strlen(str)], "]"); 875 return(str); 876} 877 878 879 880#ifdef TW_OSL_DEBUG 881 882/* 883 * Function name: tw_cl_print_ctlr_stats 884 * Description: Prints the current status of the controller. 885 * 886 * Input: ctlr_handle-- controller handle 887 * Output: None 888 * Return value: None 889 */ 890TW_VOID 891tw_cl_print_ctlr_stats(struct tw_cl_ctlr_handle *ctlr_handle) 892{ 893 struct tw_cli_ctlr_context *ctlr = 894 (struct tw_cli_ctlr_context *)(ctlr_handle->cl_ctlr_ctxt); 895 TW_UINT32 status_reg; 896 TW_INT8 desc[200]; 897 898 tw_cli_dbg_printf(7, ctlr->ctlr_handle, "", "entered"); 899 900 /* Print current controller details. */ 901 tw_cli_dbg_printf(0, ctlr_handle, "", "cl_ctlr_ctxt = %p", ctlr); 902 903 tw_osl_memzero(desc, 200); 904 status_reg = TW_CLI_READ_STATUS_REGISTER(ctlr_handle); 905 tw_cli_dbg_printf(0, ctlr_handle, "", "status reg = 0x%x %s", 906 status_reg, tw_cli_describe_bits(status_reg, desc)); 907 908 tw_cli_dbg_printf(0, ctlr_handle, "", "CLq type current max"); 909 tw_cli_dbg_printf(0, ctlr_handle, "", "free %04d %04d", 910 ctlr->q_stats[TW_CLI_FREE_Q].cur_len, 911 ctlr->q_stats[TW_CLI_FREE_Q].max_len); 912 tw_cli_dbg_printf(0, ctlr_handle, "", "busy %04d %04d", 913 ctlr->q_stats[TW_CLI_BUSY_Q].cur_len, 914 ctlr->q_stats[TW_CLI_BUSY_Q].max_len); 915 tw_cli_dbg_printf(0, ctlr_handle, "", "pending %04d %04d", 916 ctlr->q_stats[TW_CLI_PENDING_Q].cur_len, 917 ctlr->q_stats[TW_CLI_PENDING_Q].max_len); 918 tw_cli_dbg_printf(0, ctlr_handle, "", "complete %04d %04d", 919 ctlr->q_stats[TW_CLI_COMPLETE_Q].cur_len, 920 ctlr->q_stats[TW_CLI_COMPLETE_Q].max_len); 921 tw_cli_dbg_printf(0, ctlr_handle, "", "AEN queue head %d tail %d", 922 ctlr->aen_head, ctlr->aen_tail); 923} 924 925 926 927/* 928 * Function name: tw_cl_reset_stats 929 * Description: Resets CL maintained statistics for the controller. 930 * 931 * Input: ctlr_handle-- controller handle 932 * Output: None 933 * Return value: None 934 */ 935TW_VOID 936tw_cl_reset_stats(struct tw_cl_ctlr_handle *ctlr_handle) 937{ 938 struct tw_cli_ctlr_context *ctlr = 939 (struct tw_cli_ctlr_context *)(ctlr_handle->cl_ctlr_ctxt); 940 941 tw_cli_dbg_printf(7, ctlr_handle, tw_osl_cur_func(), "entered"); 942 ctlr->q_stats[TW_CLI_FREE_Q].max_len = 0; 943 ctlr->q_stats[TW_CLI_BUSY_Q].max_len = 0; 944 ctlr->q_stats[TW_CLI_PENDING_Q].max_len = 0; 945 ctlr->q_stats[TW_CLI_COMPLETE_Q].max_len = 0; 946} 947 948 949 950/* 951 * Function name: tw_cli_print_req_info 952 * Description: Prints CL internal details of a given request. 953 * 954 * Input: req -- ptr to CL internal request context 955 * Output: None 956 * Return value: None 957 */ 958TW_VOID 959tw_cl_print_req_info(struct tw_cl_req_handle *req_handle) 960{ 961 struct tw_cli_req_context *req = req_handle->cl_req_ctxt; 962 struct tw_cli_ctlr_context *ctlr = req->ctlr; 963 struct tw_cl_ctlr_handle *ctlr_handle = ctlr->ctlr_handle; 964 struct tw_cl_command_packet *cmd_pkt = req->cmd_pkt; 965 struct tw_cl_command_9k *cmd9k; 966 union tw_cl_command_7k *cmd7k; 967 TW_UINT8 *cdb; 968 TW_VOID *sgl; 969 TW_UINT32 sgl_entries; 970 TW_UINT32 i; 971 972 tw_cli_dbg_printf(0, ctlr_handle, tw_osl_cur_func(), 973 "CL details for request:"); 974 tw_cli_dbg_printf(0, ctlr_handle, tw_osl_cur_func(), 975 "req_handle = %p, ctlr = %p,\n" 976 "cmd_pkt = %p, cmd_pkt_phys = 0x%llx,\n" 977 "data = %p, length = 0x%x, data_phys = 0x%llx,\n" 978 "state = 0x%x, flags = 0x%x, error = 0x%x,\n" 979 "orig_req = %p, callback = %p, req_id = 0x%x,\n" 980 "next_req = %p, prev_req = %p", 981 req_handle, ctlr, 982 cmd_pkt, req->cmd_pkt_phys, 983 req->data, req->length, req->data_phys, 984 req->state, req->flags, req->error_code, 985 req->orig_req, req->tw_cli_callback, req->request_id, 986 req->link.next, req->link.prev); 987 988 if (req->flags & TW_CLI_REQ_FLAGS_9K) { 989 cmd9k = &(cmd_pkt->command.cmd_pkt_9k); 990 sgl = cmd9k->sg_list; 991 sgl_entries = TW_CL_SWAP16( 992 GET_SGL_ENTRIES(cmd9k->lun_h4__sgl_entries)); 993 tw_cli_dbg_printf(0, ctlr_handle, tw_osl_cur_func(), 994 "9K cmd: opcode = 0x%x, unit = 0x%x, req_id = 0x%x,\n" 995 "status = 0x%x, sgl_offset = 0x%x, sgl_entries = 0x%x", 996 GET_OPCODE(cmd9k->res__opcode), 997 cmd9k->unit, 998 TW_CL_SWAP16(GET_REQ_ID(cmd9k->lun_l4__req_id)), 999 cmd9k->status, 1000 cmd9k->sgl_offset, 1001 sgl_entries); 1002 1003 cdb = (TW_UINT8 *)(cmd9k->cdb); 1004 tw_cli_dbg_printf(0, ctlr_handle, tw_osl_cur_func(), 1005 "CDB: %x %x %x %x %x %x %x %x" 1006 "%x %x %x %x %x %x %x %x", 1007 cdb[0], cdb[1], cdb[2], cdb[3], 1008 cdb[4], cdb[5], cdb[6], cdb[7], 1009 cdb[8], cdb[9], cdb[10], cdb[11], 1010 cdb[12], cdb[13], cdb[14], cdb[15]); 1011 } else { 1012 cmd7k = &(cmd_pkt->command.cmd_pkt_7k); 1013 sgl = cmd7k->param.sgl; 1014 sgl_entries = (cmd7k->generic.size - 1015 GET_SGL_OFF(cmd7k->generic.sgl_off__opcode)) / 1016 ((ctlr->flags & TW_CL_64BIT_ADDRESSES) ? 3 : 2); 1017 tw_cli_dbg_printf(0, ctlr_handle, tw_osl_cur_func(), 1018 "7K cmd: opcode = 0x%x, sgl_offset = 0x%x,\n" 1019 "size = 0x%x, req_id = 0x%x, unit = 0x%x,\n" 1020 "status = 0x%x, flags = 0x%x, count = 0x%x", 1021 GET_OPCODE(cmd7k->generic.sgl_off__opcode), 1022 GET_SGL_OFF(cmd7k->generic.sgl_off__opcode), 1023 cmd7k->generic.size, 1024 TW_CL_SWAP16(cmd7k->generic.request_id), 1025 GET_UNIT(cmd7k->generic.host_id__unit), 1026 cmd7k->generic.status, 1027 cmd7k->generic.flags, 1028 TW_CL_SWAP16(cmd7k->generic.count)); 1029 } 1030 1031 tw_cli_dbg_printf(0, ctlr_handle, tw_osl_cur_func(), "SG entries:"); 1032 1033 if (ctlr->flags & TW_CL_64BIT_ADDRESSES) { 1034 struct tw_cl_sg_desc64 *sgl64 = (struct tw_cl_sg_desc64 *)sgl; 1035 1036 for (i = 0; i < sgl_entries; i++) { 1037 tw_cli_dbg_printf(0, ctlr_handle, tw_osl_cur_func(), 1038 "0x%llx 0x%x", 1039 sgl64[i].address, sgl64[i].length); 1040 } 1041 } else { 1042 struct tw_cl_sg_desc32 *sgl32 = (struct tw_cl_sg_desc32 *)sgl; 1043 1044 for (i = 0; i < sgl_entries; i++) { 1045 tw_cli_dbg_printf(0, ctlr_handle, tw_osl_cur_func(), 1046 "0x%x 0x%x", 1047 sgl32[i].address, sgl32[i].length); 1048 } 1049 } 1050} 1051 1052#endif /* TW_OSL_DEBUG */ 1053 1054