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