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