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