tw_cl_intr.c revision 330897
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: stable/11/sys/dev/twa/tw_cl_intr.c 330897 2018-03-14 03:19:51Z eadler $ 30 */ 31 32/* 33 * AMCC'S 3ware driver for 9000 series storage controllers. 34 * 35 * Author: Vinod Kashyap 36 * Modifications by: Adam Radford 37 * Modifications by: Manjunath Ranganathaiah 38 */ 39 40 41/* 42 * Common Layer interrupt handling functions. 43 */ 44 45 46#include "tw_osl_share.h" 47#include "tw_cl_share.h" 48#include "tw_cl_fwif.h" 49#include "tw_cl_ioctl.h" 50#include "tw_cl.h" 51#include "tw_cl_externs.h" 52#include "tw_osl_ioctl.h" 53 54 55 56/* 57 * Function name: twa_interrupt 58 * Description: Interrupt handler. Determines the kind of interrupt, 59 * and returns TW_CL_TRUE if it recognizes the interrupt. 60 * 61 * Input: ctlr_handle -- controller handle 62 * Output: None 63 * Return value: TW_CL_TRUE -- interrupt recognized 64 * TW_CL_FALSE-- interrupt not recognized 65 */ 66TW_INT32 67tw_cl_interrupt(struct tw_cl_ctlr_handle *ctlr_handle) 68{ 69 struct tw_cli_ctlr_context *ctlr = 70 (struct tw_cli_ctlr_context *)(ctlr_handle->cl_ctlr_ctxt); 71 TW_UINT32 status_reg; 72 TW_INT32 rc = TW_CL_FALSE; 73 74 tw_cli_dbg_printf(10, ctlr_handle, tw_osl_cur_func(), "entered"); 75 76 /* If we don't have controller context, bail */ 77 if (ctlr == NULL) 78 goto out; 79 80 /* 81 * Bail If we get an interrupt while resetting, or shutting down. 82 */ 83 if (ctlr->reset_in_progress || !(ctlr->active)) 84 goto out; 85 86 /* Read the status register to determine the type of interrupt. */ 87 status_reg = TW_CLI_READ_STATUS_REGISTER(ctlr_handle); 88 if (tw_cli_check_ctlr_state(ctlr, status_reg)) 89 goto out; 90 91 /* Clear the interrupt. */ 92 if (status_reg & TWA_STATUS_HOST_INTERRUPT) { 93 tw_cli_dbg_printf(6, ctlr_handle, tw_osl_cur_func(), 94 "Host interrupt"); 95 TW_CLI_WRITE_CONTROL_REGISTER(ctlr_handle, 96 TWA_CONTROL_CLEAR_HOST_INTERRUPT); 97 } 98 if (status_reg & TWA_STATUS_ATTENTION_INTERRUPT) { 99 tw_cli_dbg_printf(6, ctlr_handle, tw_osl_cur_func(), 100 "Attention interrupt"); 101 rc |= TW_CL_TRUE; /* request for a deferred isr call */ 102 tw_cli_process_attn_intr(ctlr); 103 TW_CLI_WRITE_CONTROL_REGISTER(ctlr_handle, 104 TWA_CONTROL_CLEAR_ATTENTION_INTERRUPT); 105 } 106 if (status_reg & TWA_STATUS_COMMAND_INTERRUPT) { 107 tw_cli_dbg_printf(6, ctlr_handle, tw_osl_cur_func(), 108 "Command interrupt"); 109 rc |= TW_CL_TRUE; /* request for a deferred isr call */ 110 tw_cli_process_cmd_intr(ctlr); 111 if ((TW_CL_Q_FIRST_ITEM(&(ctlr->req_q_head[TW_CLI_PENDING_Q]))) == TW_CL_NULL) 112 TW_CLI_WRITE_CONTROL_REGISTER(ctlr_handle, 113 TWA_CONTROL_MASK_COMMAND_INTERRUPT); 114 } 115 if (status_reg & TWA_STATUS_RESPONSE_INTERRUPT) { 116 tw_cli_dbg_printf(10, ctlr_handle, tw_osl_cur_func(), 117 "Response interrupt"); 118 rc |= TW_CL_TRUE; /* request for a deferred isr call */ 119 tw_cli_process_resp_intr(ctlr); 120 } 121out: 122 return(rc); 123} 124 125 126 127/* 128 * Function name: tw_cli_process_host_intr 129 * Description: This function gets called if we triggered an interrupt. 130 * We don't use it as of now. 131 * 132 * Input: ctlr -- ptr to CL internal ctlr context 133 * Output: None 134 * Return value: None 135 */ 136TW_VOID 137tw_cli_process_host_intr(struct tw_cli_ctlr_context *ctlr) 138{ 139 tw_cli_dbg_printf(6, ctlr->ctlr_handle, tw_osl_cur_func(), "entered"); 140} 141 142 143 144/* 145 * Function name: tw_cli_process_attn_intr 146 * Description: This function gets called if the fw posted an AEN 147 * (Asynchronous Event Notification). It fetches 148 * all the AEN's that the fw might have posted. 149 * 150 * Input: ctlr -- ptr to CL internal ctlr context 151 * Output: None 152 * Return value: None 153 */ 154TW_VOID 155tw_cli_process_attn_intr(struct tw_cli_ctlr_context *ctlr) 156{ 157 TW_INT32 error; 158 159 tw_cli_dbg_printf(6, ctlr->ctlr_handle, tw_osl_cur_func(), "entered"); 160 161 if ((error = tw_cli_get_aen(ctlr))) { 162 /* 163 * If the driver is already in the process of retrieveing AEN's, 164 * we will be returned TW_OSL_EBUSY. In this case, 165 * tw_cli_param_callback or tw_cli_aen_callback will eventually 166 * retrieve the AEN this attention interrupt is for. So, we 167 * don't need to print the failure. 168 */ 169 if (error != TW_OSL_EBUSY) 170 tw_cl_create_event(ctlr->ctlr_handle, TW_CL_FALSE, 171 TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR, 172 0x1200, 0x1, TW_CL_SEVERITY_ERROR_STRING, 173 "Failed to fetch AEN", 174 "error = %d", error); 175 } 176} 177 178 179 180/* 181 * Function name: tw_cli_process_cmd_intr 182 * Description: This function gets called if we hit a queue full 183 * condition earlier, and the fw is now ready for 184 * new cmds. Submits any pending requests. 185 * 186 * Input: ctlr -- ptr to CL internal ctlr context 187 * Output: None 188 * Return value: None 189 */ 190TW_VOID 191tw_cli_process_cmd_intr(struct tw_cli_ctlr_context *ctlr) 192{ 193 tw_cli_dbg_printf(6, ctlr->ctlr_handle, tw_osl_cur_func(), "entered"); 194 195 /* Start any requests that might be in the pending queue. */ 196 tw_cli_submit_pending_queue(ctlr); 197 198 /* 199 * If tw_cli_submit_pending_queue was unsuccessful due to a "cmd queue 200 * full" condition, cmd_intr will already have been unmasked by 201 * tw_cli_submit_cmd. We don't need to do it again... simply return. 202 */ 203} 204 205 206 207/* 208 * Function name: tw_cli_process_resp_intr 209 * Description: Looks for cmd completions from fw; queues cmds completed 210 * by fw into complete queue. 211 * 212 * Input: ctlr -- ptr to CL internal ctlr context 213 * Output: None 214 * Return value: 0 -- no ctlr error 215 * non-zero-- ctlr error 216 */ 217TW_INT32 218tw_cli_process_resp_intr(struct tw_cli_ctlr_context *ctlr) 219{ 220 TW_UINT32 resp; 221 struct tw_cli_req_context *req; 222 TW_INT32 error; 223 TW_UINT32 status_reg; 224 225 tw_cli_dbg_printf(10, ctlr->ctlr_handle, tw_osl_cur_func(), "entered"); 226 227 for (;;) { 228 status_reg = TW_CLI_READ_STATUS_REGISTER(ctlr->ctlr_handle); 229 if ((error = tw_cli_check_ctlr_state(ctlr, status_reg))) 230 break; 231 if (status_reg & TWA_STATUS_RESPONSE_QUEUE_EMPTY) { 232 tw_cli_dbg_printf(7, ctlr->ctlr_handle, 233 tw_osl_cur_func(), "Response queue empty"); 234 break; 235 } 236 237 /* Response queue is not empty. */ 238 resp = TW_CLI_READ_RESPONSE_QUEUE(ctlr->ctlr_handle); 239 { 240 req = &(ctlr->req_ctxt_buf[GET_RESP_ID(resp)]); 241 } 242 243 if (req->state != TW_CLI_REQ_STATE_BUSY) { 244 tw_cl_create_event(ctlr->ctlr_handle, TW_CL_FALSE, 245 TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR, 246 0x1201, 0x1, TW_CL_SEVERITY_ERROR_STRING, 247 "Unposted command completed!!", 248 "request = %p, status = %d", 249 req, req->state); 250#ifdef TW_OSL_DEBUG 251 tw_cl_print_ctlr_stats(ctlr->ctlr_handle); 252#endif /* TW_OSL_DEBUG */ 253 continue; 254 } 255 256 /* 257 * Remove the request from the busy queue, mark it as complete, 258 * and enqueue it in the complete queue. 259 */ 260 tw_cli_req_q_remove_item(req, TW_CLI_BUSY_Q); 261 req->state = TW_CLI_REQ_STATE_COMPLETE; 262 tw_cli_req_q_insert_tail(req, TW_CLI_COMPLETE_Q); 263 264 } 265 266 /* Complete this, and other requests in the complete queue. */ 267 tw_cli_process_complete_queue(ctlr); 268 269 return(error); 270} 271 272 273 274/* 275 * Function name: tw_cli_submit_pending_queue 276 * Description: Kick starts any requests in the pending queue. 277 * 278 * Input: ctlr -- ptr to CL internal ctlr context 279 * Output: None 280 * Return value: 0 -- all pending requests submitted successfully 281 * non-zero-- otherwise 282 */ 283TW_INT32 284tw_cli_submit_pending_queue(struct tw_cli_ctlr_context *ctlr) 285{ 286 struct tw_cli_req_context *req; 287 TW_INT32 error = TW_OSL_ESUCCESS; 288 289 tw_cli_dbg_printf(3, ctlr->ctlr_handle, tw_osl_cur_func(), "entered"); 290 291 /* 292 * Pull requests off the pending queue, and submit them. 293 */ 294 while ((req = tw_cli_req_q_remove_head(ctlr, TW_CLI_PENDING_Q)) != 295 TW_CL_NULL) { 296 if ((error = tw_cli_submit_cmd(req))) { 297 if (error == TW_OSL_EBUSY) { 298 tw_cli_dbg_printf(2, ctlr->ctlr_handle, 299 tw_osl_cur_func(), 300 "Requeueing pending request"); 301 req->state = TW_CLI_REQ_STATE_PENDING; 302 /* 303 * Queue the request at the head of the pending 304 * queue, and break away, so we don't try to 305 * submit any more requests. 306 */ 307 tw_cli_req_q_insert_head(req, TW_CLI_PENDING_Q); 308 break; 309 } else { 310 tw_cl_create_event(ctlr->ctlr_handle, 311 TW_CL_FALSE, 312 TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR, 313 0x1202, 0x1, 314 TW_CL_SEVERITY_ERROR_STRING, 315 "Could not start request " 316 "in pending queue", 317 "request = %p, opcode = 0x%x, " 318 "error = %d", req, 319 GET_OPCODE(req->cmd_pkt-> 320 command.cmd_pkt_9k.res__opcode), 321 error); 322 /* 323 * Set the appropriate error and call the CL 324 * internal callback if there's one. If the 325 * request originator is polling for completion, 326 * he should be checking req->error to 327 * determine that the request did not go 328 * through. The request originators are 329 * responsible for the clean-up. 330 */ 331 req->error_code = error; 332 req->state = TW_CLI_REQ_STATE_COMPLETE; 333 if (req->tw_cli_callback) 334 req->tw_cli_callback(req); 335 error = TW_OSL_ESUCCESS; 336 } 337 } 338 } 339 return(error); 340} 341 342 343 344/* 345 * Function name: tw_cli_process_complete_queue 346 * Description: Calls the CL internal callback routine, if any, for 347 * each request in the complete queue. 348 * 349 * Input: ctlr -- ptr to CL internal ctlr context 350 * Output: None 351 * Return value: None 352 */ 353TW_VOID 354tw_cli_process_complete_queue(struct tw_cli_ctlr_context *ctlr) 355{ 356 struct tw_cli_req_context *req; 357 358 tw_cli_dbg_printf(10, ctlr->ctlr_handle, tw_osl_cur_func(), "entered"); 359 360 /* 361 * Pull commands off the completed list, dispatch them appropriately. 362 */ 363 while ((req = tw_cli_req_q_remove_head(ctlr, TW_CLI_COMPLETE_Q)) != 364 TW_CL_NULL) { 365 /* Call the CL internal callback, if there's one. */ 366 if (req->tw_cli_callback) 367 req->tw_cli_callback(req); 368 } 369} 370 371 372 373/* 374 * Function name: tw_cli_complete_io 375 * Description: CL internal callback for SCSI/fw passthru requests. 376 * 377 * Input: req -- ptr to CL internal request context 378 * Output: None 379 * Return value: None 380 */ 381TW_VOID 382tw_cli_complete_io(struct tw_cli_req_context *req) 383{ 384 struct tw_cli_ctlr_context *ctlr = req->ctlr; 385 struct tw_cl_req_packet *req_pkt = 386 (struct tw_cl_req_packet *)(req->orig_req); 387 388 tw_cli_dbg_printf(8, ctlr->ctlr_handle, tw_osl_cur_func(), "entered"); 389 390 req_pkt->status = TW_CL_ERR_REQ_SUCCESS; 391 if (req->error_code) { 392 req_pkt->status = TW_CL_ERR_REQ_UNABLE_TO_SUBMIT_COMMAND; 393 goto out; 394 } 395 396 if (req->state != TW_CLI_REQ_STATE_COMPLETE) { 397 tw_cl_create_event(ctlr->ctlr_handle, TW_CL_FALSE, 398 TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR, 399 0x1203, 0x1, TW_CL_SEVERITY_ERROR_STRING, 400 "I/O completion on incomplete command!!", 401 "request = %p, status = %d", 402 req, req->state); 403#ifdef TW_OSL_DEBUG 404 tw_cl_print_ctlr_stats(ctlr->ctlr_handle); 405#endif /* TW_OSL_DEBUG */ 406 return; 407 } 408 409 if (req->flags & TW_CLI_REQ_FLAGS_PASSTHRU) { 410 /* Copy the command packet back into OSL's space. */ 411 tw_osl_memcpy(req_pkt->gen_req_pkt.pt_req.cmd_pkt, req->cmd_pkt, 412 sizeof(struct tw_cl_command_packet)); 413 } else 414 tw_cli_scsi_complete(req); 415 416out: 417 req_pkt->tw_osl_callback(req->req_handle); 418 tw_cli_req_q_insert_tail(req, TW_CLI_FREE_Q); 419} 420 421 422 423/* 424 * Function name: tw_cli_scsi_complete 425 * Description: Completion routine for SCSI requests. 426 * 427 * Input: req -- ptr to CL internal request context 428 * Output: None 429 * Return value: None 430 */ 431TW_VOID 432tw_cli_scsi_complete(struct tw_cli_req_context *req) 433{ 434 struct tw_cl_req_packet *req_pkt = 435 (struct tw_cl_req_packet *)(req->orig_req); 436 struct tw_cl_scsi_req_packet *scsi_req = 437 &(req_pkt->gen_req_pkt.scsi_req); 438 struct tw_cl_command_9k *cmd = 439 &(req->cmd_pkt->command.cmd_pkt_9k); 440 struct tw_cl_command_header *cmd_hdr; 441 TW_UINT16 error; 442 TW_UINT8 *cdb; 443 444 tw_cli_dbg_printf(8, req->ctlr->ctlr_handle, tw_osl_cur_func(), 445 "entered"); 446 447 scsi_req->scsi_status = cmd->status; 448 if (! cmd->status) 449 return; 450 451 tw_cli_dbg_printf(1, req->ctlr->ctlr_handle, tw_osl_cur_func(), 452 "req_id = 0x%x, status = 0x%x", 453 GET_REQ_ID(cmd->lun_l4__req_id), cmd->status); 454 455 cmd_hdr = &(req->cmd_pkt->cmd_hdr); 456 error = cmd_hdr->status_block.error; 457 if ((error == TWA_ERROR_LOGICAL_UNIT_NOT_SUPPORTED) || 458 (error == TWA_ERROR_UNIT_OFFLINE)) { 459 if (GET_LUN_L4(cmd->lun_l4__req_id)) 460 req_pkt->status |= TW_CL_ERR_REQ_INVALID_LUN; 461 else 462 req_pkt->status |= TW_CL_ERR_REQ_INVALID_TARGET; 463 } else { 464 tw_cli_dbg_printf(2, req->ctlr->ctlr_handle, 465 tw_osl_cur_func(), 466 "cmd = %x %x %x %x %x %x %x", 467 GET_OPCODE(cmd->res__opcode), 468 GET_SGL_OFF(cmd->res__opcode), 469 cmd->unit, 470 cmd->lun_l4__req_id, 471 cmd->status, 472 cmd->sgl_offset, 473 cmd->lun_h4__sgl_entries); 474 475 cdb = (TW_UINT8 *)(cmd->cdb); 476 tw_cli_dbg_printf(2, req->ctlr->ctlr_handle, 477 tw_osl_cur_func(), 478 "cdb = %x %x %x %x %x %x %x %x " 479 "%x %x %x %x %x %x %x %x", 480 cdb[0], cdb[1], cdb[2], cdb[3], 481 cdb[4], cdb[5], cdb[6], cdb[7], 482 cdb[8], cdb[9], cdb[10], cdb[11], 483 cdb[12], cdb[13], cdb[14], cdb[15]); 484 485#if 0 486 /* 487 * Print the error. Firmware doesn't yet support 488 * the 'Mode Sense' cmd. Don't print if the cmd 489 * is 'Mode Sense', and the error is 'Invalid field 490 * in CDB'. 491 */ 492 if (! ((cdb[0] == 0x1A) && (error == 0x10D))) 493 tw_cli_create_ctlr_event(req->ctlr, 494 TW_CL_MESSAGE_SOURCE_CONTROLLER_ERROR, 495 cmd_hdr); 496#endif // 0 497 } 498 499 if (scsi_req->sense_data) { 500 tw_osl_memcpy(scsi_req->sense_data, cmd_hdr->sense_data, 501 TWA_SENSE_DATA_LENGTH); 502 scsi_req->sense_len = TWA_SENSE_DATA_LENGTH; 503 req_pkt->status |= TW_CL_ERR_REQ_AUTO_SENSE_VALID; 504 } 505 req_pkt->status |= TW_CL_ERR_REQ_SCSI_ERROR; 506} 507 508 509 510/* 511 * Function name: tw_cli_param_callback 512 * Description: Callback for get/set_param requests. 513 * 514 * Input: req -- ptr to completed request pkt 515 * Output: None 516 * Return value: None 517 */ 518TW_VOID 519tw_cli_param_callback(struct tw_cli_req_context *req) 520{ 521 struct tw_cli_ctlr_context *ctlr = req->ctlr; 522 union tw_cl_command_7k *cmd = 523 &(req->cmd_pkt->command.cmd_pkt_7k); 524 TW_INT32 error; 525 526 tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(), "entered"); 527 528 /* 529 * If the request was never submitted to the controller, the function 530 * that sets req->error is responsible for calling tw_cl_create_event. 531 */ 532 if (! req->error_code) 533 if (cmd->param.status) { 534#if 0 535 tw_cli_create_ctlr_event(ctlr, 536 TW_CL_MESSAGE_SOURCE_CONTROLLER_ERROR, 537 &(req->cmd_pkt->cmd_hdr)); 538#endif // 0 539 tw_cl_create_event(ctlr->ctlr_handle, TW_CL_FALSE, 540 TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR, 541 0x1204, 0x1, TW_CL_SEVERITY_ERROR_STRING, 542 "get/set_param failed", 543 "status = %d", cmd->param.status); 544 } 545 546 ctlr->internal_req_busy = TW_CL_FALSE; 547 tw_cli_req_q_insert_tail(req, TW_CLI_FREE_Q); 548 549 if ((ctlr->get_more_aens) && (!(ctlr->reset_in_progress))) { 550 ctlr->get_more_aens = TW_CL_FALSE; 551 tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(), 552 "Fetching more AEN's"); 553 if ((error = tw_cli_get_aen(ctlr))) 554 tw_cl_create_event(ctlr->ctlr_handle, TW_CL_FALSE, 555 TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR, 556 0x1205, 0x1, TW_CL_SEVERITY_ERROR_STRING, 557 "Failed to fetch all AEN's from param_callback", 558 "error = %d", error); 559 } 560} 561 562 563 564/* 565 * Function name: tw_cli_aen_callback 566 * Description: Callback for requests to fetch AEN's. 567 * 568 * Input: req -- ptr to completed request pkt 569 * Output: None 570 * Return value: None 571 */ 572TW_VOID 573tw_cli_aen_callback(struct tw_cli_req_context *req) 574{ 575 struct tw_cli_ctlr_context *ctlr = req->ctlr; 576 struct tw_cl_command_header *cmd_hdr; 577 struct tw_cl_command_9k *cmd = 578 &(req->cmd_pkt->command.cmd_pkt_9k); 579 TW_UINT16 aen_code = TWA_AEN_QUEUE_EMPTY; 580 TW_INT32 error; 581 582 tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(), "entered"); 583 584 tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(), 585 "req_id = 0x%x, req error = %d, status = 0x%x", 586 GET_REQ_ID(cmd->lun_l4__req_id), req->error_code, cmd->status); 587 588 /* 589 * If the request was never submitted to the controller, the function 590 * that sets error is responsible for calling tw_cl_create_event. 591 */ 592 if (!(error = req->error_code)) 593 if ((error = cmd->status)) { 594 cmd_hdr = (struct tw_cl_command_header *) 595 (&(req->cmd_pkt->cmd_hdr)); 596#if 0 597 tw_cli_create_ctlr_event(ctlr, 598 TW_CL_MESSAGE_SOURCE_CONTROLLER_ERROR, 599 cmd_hdr); 600#endif // 0 601 tw_cl_create_event(ctlr->ctlr_handle, TW_CL_FALSE, 602 TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR, 603 0x1206, 0x1, TW_CL_SEVERITY_ERROR_STRING, 604 "Request Sense failed", 605 "opcode = 0x%x, status = %d", 606 GET_OPCODE(cmd->res__opcode), cmd->status); 607 } 608 609 if (error) { 610 ctlr->internal_req_busy = TW_CL_FALSE; 611 tw_cli_req_q_insert_tail(req, TW_CLI_FREE_Q); 612 return; 613 } 614 615 tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(), 616 "Request Sense command succeeded"); 617 618 aen_code = tw_cli_manage_aen(ctlr, req); 619 620 if (aen_code != TWA_AEN_SYNC_TIME_WITH_HOST) { 621 ctlr->internal_req_busy = TW_CL_FALSE; 622 tw_cli_req_q_insert_tail(req, TW_CLI_FREE_Q); 623 if (aen_code != TWA_AEN_QUEUE_EMPTY) 624 if ((error = tw_cli_get_aen(ctlr))) 625 tw_cl_create_event(ctlr->ctlr_handle, 626 TW_CL_FALSE, 627 TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR, 628 0x1207, 0x1, 629 TW_CL_SEVERITY_ERROR_STRING, 630 "Failed to fetch all AEN's", 631 "error = %d", error); 632 } 633} 634 635 636 637/* 638 * Function name: tw_cli_manage_aen 639 * Description: Handles AEN's. 640 * 641 * Input: ctlr -- ptr to CL internal ctlr context 642 * req -- ptr to CL internal request context 643 * Output: None 644 * Return value: None 645 */ 646TW_UINT16 647tw_cli_manage_aen(struct tw_cli_ctlr_context *ctlr, 648 struct tw_cli_req_context *req) 649{ 650 struct tw_cl_command_header *cmd_hdr; 651 TW_UINT16 aen_code; 652 TW_TIME local_time; 653 TW_TIME sync_time; 654 TW_UINT32 error; 655 656 tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(), "entered"); 657 658 cmd_hdr = (struct tw_cl_command_header *)(req->data); 659 aen_code = cmd_hdr->status_block.error; 660 661 switch (aen_code) { 662 case TWA_AEN_SYNC_TIME_WITH_HOST: 663 tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(), 664 "Received AEN_SYNC_TIME"); 665 /* 666 * Free the internal req pkt right here, since 667 * tw_cli_set_param will need it. 668 */ 669 ctlr->internal_req_busy = TW_CL_FALSE; 670 tw_cli_req_q_insert_tail(req, TW_CLI_FREE_Q); 671 672 /* 673 * We will use a callback in tw_cli_set_param only when 674 * interrupts are enabled and we can expect our callback 675 * to get called. Setting the get_more_aens 676 * flag will make the callback continue to try to retrieve 677 * more AEN's. 678 */ 679 if (ctlr->interrupts_enabled) 680 ctlr->get_more_aens = TW_CL_TRUE; 681 /* Calculate time (in seconds) since last Sunday 12.00 AM. */ 682 local_time = tw_osl_get_local_time(); 683 sync_time = (local_time - (3 * 86400)) % 604800; 684 if ((error = tw_cli_set_param(ctlr, TWA_PARAM_TIME_TABLE, 685 TWA_PARAM_TIME_SCHED_TIME, 4, 686 &sync_time, 687 (ctlr->interrupts_enabled) 688 ? tw_cli_param_callback : TW_CL_NULL))) 689 tw_cl_create_event(ctlr->ctlr_handle, TW_CL_FALSE, 690 TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR, 691 0x1208, 0x1, TW_CL_SEVERITY_ERROR_STRING, 692 "Unable to sync time with ctlr", 693 "error = %d", error); 694 695 break; 696 697 698 case TWA_AEN_QUEUE_EMPTY: 699 tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(), 700 "AEN queue empty"); 701 break; 702 703 704 default: 705 /* Queue the event. */ 706 707 tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(), 708 "Queueing AEN"); 709 tw_cli_create_ctlr_event(ctlr, 710 TW_CL_MESSAGE_SOURCE_CONTROLLER_EVENT, 711 cmd_hdr); 712 break; 713 } /* switch */ 714 return(aen_code); 715} 716 717 718 719/* 720 * Function name: tw_cli_enable_interrupts 721 * Description: Enables interrupts on the controller 722 * 723 * Input: ctlr -- ptr to CL internal ctlr context 724 * Output: None 725 * Return value: None 726 */ 727TW_VOID 728tw_cli_enable_interrupts(struct tw_cli_ctlr_context *ctlr) 729{ 730 tw_cli_dbg_printf(3, ctlr->ctlr_handle, tw_osl_cur_func(), "entered"); 731 732 ctlr->interrupts_enabled = TW_CL_TRUE; 733 TW_CLI_WRITE_CONTROL_REGISTER(ctlr->ctlr_handle, 734 TWA_CONTROL_CLEAR_ATTENTION_INTERRUPT | 735 TWA_CONTROL_UNMASK_RESPONSE_INTERRUPT | 736 TWA_CONTROL_ENABLE_INTERRUPTS); 737} 738 739 740 741/* 742 * Function name: twa_setup 743 * Description: Disables interrupts on the controller 744 * 745 * Input: ctlr -- ptr to CL internal ctlr context 746 * Output: None 747 * Return value: None 748 */ 749TW_VOID 750tw_cli_disable_interrupts(struct tw_cli_ctlr_context *ctlr) 751{ 752 tw_cli_dbg_printf(3, ctlr->ctlr_handle, tw_osl_cur_func(), "entered"); 753 754 TW_CLI_WRITE_CONTROL_REGISTER(ctlr->ctlr_handle, 755 TWA_CONTROL_DISABLE_INTERRUPTS); 756 ctlr->interrupts_enabled = TW_CL_FALSE; 757} 758 759