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: src/sys/dev/twa/tw_cl_intr.c,v 1.5 2010/06/09 21:40:38 delphij Exp $ 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 tw_cl_reset_ctlr(ctlr->ctlr_handle); 252 return(TW_OSL_EIO); 253 } 254 255 /* 256 * Remove the request from the busy queue, mark it as complete, 257 * and enqueue it in the complete queue. 258 */ 259 tw_cli_req_q_remove_item(req, TW_CLI_BUSY_Q); 260 req->state = TW_CLI_REQ_STATE_COMPLETE; 261 tw_cli_req_q_insert_tail(req, TW_CLI_COMPLETE_Q); 262 263 } 264 265 /* Complete this, and other requests in the complete queue. */ 266 tw_cli_process_complete_queue(ctlr); 267 268 return(error); 269 } 270 271 272 273 /* 274 * Function name: tw_cli_submit_pending_queue 275 * Description: Kick starts any requests in the pending queue. 276 * 277 * Input: ctlr -- ptr to CL internal ctlr context 278 * Output: None 279 * Return value: 0 -- all pending requests submitted successfully 280 * non-zero-- otherwise 281 */ 282 TW_INT32 283 tw_cli_submit_pending_queue(struct tw_cli_ctlr_context *ctlr) 284 { 285 struct tw_cli_req_context *req; 286 TW_INT32 error = TW_OSL_ESUCCESS; 287 288 tw_cli_dbg_printf(3, ctlr->ctlr_handle, tw_osl_cur_func(), "entered"); 289 290 /* 291 * Pull requests off the pending queue, and submit them. 292 */ 293 while ((req = tw_cli_req_q_remove_head(ctlr, TW_CLI_PENDING_Q)) != 294 TW_CL_NULL) { 295 if ((error = tw_cli_submit_cmd(req))) { 296 if (error == TW_OSL_EBUSY) { 297 tw_cli_dbg_printf(2, ctlr->ctlr_handle, 298 tw_osl_cur_func(), 299 "Requeueing pending request"); 300 req->state = TW_CLI_REQ_STATE_PENDING; 301 /* 302 * Queue the request at the head of the pending 303 * queue, and break away, so we don't try to 304 * submit any more requests. 305 */ 306 tw_cli_req_q_insert_head(req, TW_CLI_PENDING_Q); 307 break; 308 } else { 309 tw_cl_create_event(ctlr->ctlr_handle, 310 TW_CL_FALSE, 311 TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR, 312 0x1202, 0x1, 313 TW_CL_SEVERITY_ERROR_STRING, 314 "Could not start request " 315 "in pending queue", 316 "request = %p, opcode = 0x%x, " 317 "error = %d", req, 318 GET_OPCODE(req->cmd_pkt-> 319 command.cmd_pkt_9k.res__opcode), 320 error); 321 /* 322 * Set the appropriate error and call the CL 323 * internal callback if there's one. If the 324 * request originator is polling for completion, 325 * he should be checking req->error to 326 * determine that the request did not go 327 * through. The request originators are 328 * responsible for the clean-up. 329 */ 330 req->error_code = error; 331 req->state = TW_CLI_REQ_STATE_COMPLETE; 332 if (req->tw_cli_callback) 333 req->tw_cli_callback(req); 334 error = TW_OSL_ESUCCESS; 335 } 336 } 337 } 338 return(error); 339 } 340 341 342 343 /* 344 * Function name: tw_cli_process_complete_queue 345 * Description: Calls the CL internal callback routine, if any, for 346 * each request in the complete queue. 347 * 348 * Input: ctlr -- ptr to CL internal ctlr context 349 * Output: None 350 * Return value: None 351 */ 352 TW_VOID 353 tw_cli_process_complete_queue(struct tw_cli_ctlr_context *ctlr) 354 { 355 struct tw_cli_req_context *req; 356 357 tw_cli_dbg_printf(10, ctlr->ctlr_handle, tw_osl_cur_func(), "entered"); 358 359 /* 360 * Pull commands off the completed list, dispatch them appropriately. 361 */ 362 while ((req = tw_cli_req_q_remove_head(ctlr, TW_CLI_COMPLETE_Q)) != 363 TW_CL_NULL) { 364 /* Call the CL internal callback, if there's one. */ 365 if (req->tw_cli_callback) 366 req->tw_cli_callback(req); 367 } 368 } 369 370 371 372 /* 373 * Function name: tw_cli_complete_io 374 * Description: CL internal callback for SCSI/fw passthru requests. 375 * 376 * Input: req -- ptr to CL internal request context 377 * Output: None 378 * Return value: None 379 */ 380 TW_VOID 381 tw_cli_complete_io(struct tw_cli_req_context *req) 382 { 383 struct tw_cli_ctlr_context *ctlr = req->ctlr; 384 struct tw_cl_req_packet *req_pkt = 385 (struct tw_cl_req_packet *)(req->orig_req); 386 387 tw_cli_dbg_printf(8, ctlr->ctlr_handle, tw_osl_cur_func(), "entered"); 388 389 req_pkt->status = TW_CL_ERR_REQ_SUCCESS; 390 if (req->error_code) { 391 req_pkt->status = TW_CL_ERR_REQ_UNABLE_TO_SUBMIT_COMMAND; 392 goto out; 393 } 394 395 if (req->state != TW_CLI_REQ_STATE_COMPLETE) { 396 tw_cl_create_event(ctlr->ctlr_handle, TW_CL_FALSE, 397 TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR, 398 0x1203, 0x1, TW_CL_SEVERITY_ERROR_STRING, 399 "I/O completion on incomplete command!!", 400 "request = %p, status = %d", 401 req, req->state); 402 #ifdef TW_OSL_DEBUG 403 tw_cl_print_ctlr_stats(ctlr->ctlr_handle); 404 #endif /* TW_OSL_DEBUG */ 405 tw_cl_reset_ctlr(ctlr->ctlr_handle); 406 req_pkt->status = TW_CL_ERR_REQ_BUS_RESET; 407 goto out; 408 } 409 410 if (req->flags & TW_CLI_REQ_FLAGS_PASSTHRU) { 411 /* Copy the command packet back into OSL's space. */ 412 tw_osl_memcpy(req_pkt->gen_req_pkt.pt_req.cmd_pkt, req->cmd_pkt, 413 sizeof(struct tw_cl_command_packet)); 414 } else 415 tw_cli_scsi_complete(req); 416 417 out: 418 req_pkt->tw_osl_callback(req->req_handle); 419 tw_cli_req_q_insert_tail(req, TW_CLI_FREE_Q); 420 } 421 422 423 424 /* 425 * Function name: tw_cli_scsi_complete 426 * Description: Completion routine for SCSI requests. 427 * 428 * Input: req -- ptr to CL internal request context 429 * Output: None 430 * Return value: None 431 */ 432 TW_VOID 433 tw_cli_scsi_complete(struct tw_cli_req_context *req) 434 { 435 struct tw_cl_req_packet *req_pkt = 436 (struct tw_cl_req_packet *)(req->orig_req); 437 struct tw_cl_scsi_req_packet *scsi_req = 438 &(req_pkt->gen_req_pkt.scsi_req); 439 struct tw_cl_command_9k *cmd = 440 &(req->cmd_pkt->command.cmd_pkt_9k); 441 struct tw_cl_command_header *cmd_hdr; 442 TW_UINT16 error; 443 TW_UINT8 *cdb; 444 445 tw_cli_dbg_printf(8, req->ctlr->ctlr_handle, tw_osl_cur_func(), 446 "entered"); 447 448 scsi_req->scsi_status = cmd->status; 449 if (! cmd->status) 450 return; 451 452 tw_cli_dbg_printf(1, req->ctlr->ctlr_handle, tw_osl_cur_func(), 453 "req_id = 0x%x, status = 0x%x", 454 GET_REQ_ID(cmd->lun_l4__req_id), cmd->status); 455 456 cmd_hdr = &(req->cmd_pkt->cmd_hdr); 457 error = cmd_hdr->status_block.error; 458 if ((error == TWA_ERROR_LOGICAL_UNIT_NOT_SUPPORTED) || 459 (error == TWA_ERROR_UNIT_OFFLINE)) { 460 if (GET_LUN_L4(cmd->lun_l4__req_id)) 461 req_pkt->status |= TW_CL_ERR_REQ_INVALID_LUN; 462 else 463 req_pkt->status |= TW_CL_ERR_REQ_INVALID_TARGET; 464 } else { 465 tw_cli_dbg_printf(2, req->ctlr->ctlr_handle, 466 tw_osl_cur_func(), 467 "cmd = %x %x %x %x %x %x %x", 468 GET_OPCODE(cmd->res__opcode), 469 GET_SGL_OFF(cmd->res__opcode), 470 cmd->unit, 471 cmd->lun_l4__req_id, 472 cmd->status, 473 cmd->sgl_offset, 474 cmd->lun_h4__sgl_entries); 475 476 cdb = (TW_UINT8 *)(cmd->cdb); 477 tw_cli_dbg_printf(2, req->ctlr->ctlr_handle, 478 tw_osl_cur_func(), 479 "cdb = %x %x %x %x %x %x %x %x " 480 "%x %x %x %x %x %x %x %x", 481 cdb[0], cdb[1], cdb[2], cdb[3], 482 cdb[4], cdb[5], cdb[6], cdb[7], 483 cdb[8], cdb[9], cdb[10], cdb[11], 484 cdb[12], cdb[13], cdb[14], cdb[15]); 485 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 } 497 498 if (scsi_req->sense_data) { 499 tw_osl_memcpy(scsi_req->sense_data, cmd_hdr->sense_data, 500 TWA_SENSE_DATA_LENGTH); 501 scsi_req->sense_len = TWA_SENSE_DATA_LENGTH; 502 req_pkt->status |= TW_CL_ERR_REQ_AUTO_SENSE_VALID; 503 } 504 req_pkt->status |= TW_CL_ERR_REQ_SCSI_ERROR; 505 } 506 507 508 509 /* 510 * Function name: tw_cli_param_callback 511 * Description: Callback for get/set_param requests. 512 * 513 * Input: req -- ptr to completed request pkt 514 * Output: None 515 * Return value: None 516 */ 517 TW_VOID 518 tw_cli_param_callback(struct tw_cli_req_context *req) 519 { 520 struct tw_cli_ctlr_context *ctlr = req->ctlr; 521 union tw_cl_command_7k *cmd = 522 &(req->cmd_pkt->command.cmd_pkt_7k); 523 TW_INT32 error; 524 525 tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(), "entered"); 526 527 /* 528 * If the request was never submitted to the controller, the function 529 * that sets req->error is responsible for calling tw_cl_create_event. 530 */ 531 if (! req->error_code) 532 if (cmd->param.status) { 533 tw_cli_create_ctlr_event(ctlr, 534 TW_CL_MESSAGE_SOURCE_CONTROLLER_ERROR, 535 &(req->cmd_pkt->cmd_hdr)); 536 tw_cl_create_event(ctlr->ctlr_handle, TW_CL_FALSE, 537 TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR, 538 0x1204, 0x1, TW_CL_SEVERITY_ERROR_STRING, 539 "get/set_param failed", 540 "status = %d", cmd->param.status); 541 } 542 543 ctlr->internal_req_busy = TW_CL_FALSE; 544 tw_cli_req_q_insert_tail(req, TW_CLI_FREE_Q); 545 546 if ((ctlr->get_more_aens) && (!(ctlr->reset_in_progress))) { 547 ctlr->get_more_aens = TW_CL_FALSE; 548 tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(), 549 "Fetching more AEN's"); 550 if ((error = tw_cli_get_aen(ctlr))) 551 tw_cl_create_event(ctlr->ctlr_handle, TW_CL_FALSE, 552 TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR, 553 0x1205, 0x1, TW_CL_SEVERITY_ERROR_STRING, 554 "Failed to fetch all AEN's from param_callback", 555 "error = %d", error); 556 } 557 } 558 559 560 561 /* 562 * Function name: tw_cli_aen_callback 563 * Description: Callback for requests to fetch AEN's. 564 * 565 * Input: req -- ptr to completed request pkt 566 * Output: None 567 * Return value: None 568 */ 569 TW_VOID 570 tw_cli_aen_callback(struct tw_cli_req_context *req) 571 { 572 struct tw_cli_ctlr_context *ctlr = req->ctlr; 573 struct tw_cl_command_header *cmd_hdr; 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 cmd_hdr = (struct tw_cl_command_header *) 592 (&(req->cmd_pkt->cmd_hdr)); 593 tw_cli_create_ctlr_event(ctlr, 594 TW_CL_MESSAGE_SOURCE_CONTROLLER_ERROR, 595 cmd_hdr); 596 tw_cl_create_event(ctlr->ctlr_handle, TW_CL_FALSE, 597 TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR, 598 0x1206, 0x1, TW_CL_SEVERITY_ERROR_STRING, 599 "Request Sense failed", 600 "opcode = 0x%x, status = %d", 601 GET_OPCODE(cmd->res__opcode), cmd->status); 602 } 603 604 if (error) { 605 ctlr->internal_req_busy = TW_CL_FALSE; 606 tw_cli_req_q_insert_tail(req, TW_CLI_FREE_Q); 607 return; 608 } 609 610 tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(), 611 "Request Sense command succeeded"); 612 613 aen_code = tw_cli_manage_aen(ctlr, req); 614 615 if (aen_code != TWA_AEN_SYNC_TIME_WITH_HOST) { 616 ctlr->internal_req_busy = TW_CL_FALSE; 617 tw_cli_req_q_insert_tail(req, TW_CLI_FREE_Q); 618 if (aen_code != TWA_AEN_QUEUE_EMPTY) 619 if ((error = tw_cli_get_aen(ctlr))) 620 tw_cl_create_event(ctlr->ctlr_handle, 621 TW_CL_FALSE, 622 TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR, 623 0x1207, 0x1, 624 TW_CL_SEVERITY_ERROR_STRING, 625 "Failed to fetch all AEN's", 626 "error = %d", error); 627 } 628 } 629 630 631 632 /* 633 * Function name: tw_cli_manage_aen 634 * Description: Handles AEN's. 635 * 636 * Input: ctlr -- ptr to CL internal ctlr context 637 * req -- ptr to CL internal request context 638 * Output: None 639 * Return value: None 640 */ 641 TW_UINT16 642 tw_cli_manage_aen(struct tw_cli_ctlr_context *ctlr, 643 struct tw_cli_req_context *req) 644 { 645 struct tw_cl_command_header *cmd_hdr; 646 TW_UINT16 aen_code; 647 TW_TIME local_time; 648 TW_TIME sync_time; 649 TW_UINT32 error; 650 651 tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(), "entered"); 652 653 cmd_hdr = (struct tw_cl_command_header *)(req->data); 654 aen_code = cmd_hdr->status_block.error; 655 656 switch (aen_code) { 657 case TWA_AEN_SYNC_TIME_WITH_HOST: 658 tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(), 659 "Received AEN_SYNC_TIME"); 660 /* 661 * Free the internal req pkt right here, since 662 * tw_cli_set_param will need it. 663 */ 664 ctlr->internal_req_busy = TW_CL_FALSE; 665 tw_cli_req_q_insert_tail(req, TW_CLI_FREE_Q); 666 667 /* 668 * We will use a callback in tw_cli_set_param only when 669 * interrupts are enabled and we can expect our callback 670 * to get called. Setting the get_more_aens 671 * flag will make the callback continue to try to retrieve 672 * more AEN's. 673 */ 674 if (ctlr->interrupts_enabled) 675 ctlr->get_more_aens = TW_CL_TRUE; 676 /* Calculate time (in seconds) since last Sunday 12.00 AM. */ 677 local_time = tw_osl_get_local_time(); 678 sync_time = (local_time - (3 * 86400)) % 604800; 679 if ((error = tw_cli_set_param(ctlr, TWA_PARAM_TIME_TABLE, 680 TWA_PARAM_TIME_SCHED_TIME, 4, 681 &sync_time, 682 (ctlr->interrupts_enabled) 683 ? tw_cli_param_callback : TW_CL_NULL))) 684 tw_cl_create_event(ctlr->ctlr_handle, TW_CL_FALSE, 685 TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR, 686 0x1208, 0x1, TW_CL_SEVERITY_ERROR_STRING, 687 "Unable to sync time with ctlr", 688 "error = %d", error); 689 690 break; 691 692 693 case TWA_AEN_QUEUE_EMPTY: 694 tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(), 695 "AEN queue empty"); 696 break; 697 698 699 default: 700 /* Queue the event. */ 701 702 tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(), 703 "Queueing AEN"); 704 tw_cli_create_ctlr_event(ctlr, 705 TW_CL_MESSAGE_SOURCE_CONTROLLER_EVENT, 706 cmd_hdr); 707 break; 708 } /* switch */ 709 return(aen_code); 710 } 711 712 713 714 /* 715 * Function name: tw_cli_enable_interrupts 716 * Description: Enables interrupts on the controller 717 * 718 * Input: ctlr -- ptr to CL internal ctlr context 719 * Output: None 720 * Return value: None 721 */ 722 TW_VOID 723 tw_cli_enable_interrupts(struct tw_cli_ctlr_context *ctlr) 724 { 725 tw_cli_dbg_printf(3, ctlr->ctlr_handle, tw_osl_cur_func(), "entered"); 726 727 ctlr->interrupts_enabled = TW_CL_TRUE; 728 TW_CLI_WRITE_CONTROL_REGISTER(ctlr->ctlr_handle, 729 TWA_CONTROL_CLEAR_ATTENTION_INTERRUPT | 730 TWA_CONTROL_UNMASK_RESPONSE_INTERRUPT | 731 TWA_CONTROL_ENABLE_INTERRUPTS); 732 } 733 734 735 736 /* 737 * Function name: twa_setup 738 * Description: Disables interrupts on the controller 739 * 740 * Input: ctlr -- ptr to CL internal ctlr context 741 * Output: None 742 * Return value: None 743 */ 744 TW_VOID 745 tw_cli_disable_interrupts(struct tw_cli_ctlr_context *ctlr) 746 { 747 tw_cli_dbg_printf(3, ctlr->ctlr_handle, tw_osl_cur_func(), "entered"); 748 749 TW_CLI_WRITE_CONTROL_REGISTER(ctlr->ctlr_handle, 750 TWA_CONTROL_DISABLE_INTERRUPTS); 751 ctlr->interrupts_enabled = TW_CL_FALSE; 752 } 753