1144966Svkashyap/* 2169400Sscottl * Copyright (c) 2004-07 Applied Micro Circuits Corporation. 3144966Svkashyap * Copyright (c) 2004-05 Vinod Kashyap 4144966Svkashyap * All rights reserved. 5144966Svkashyap * 6144966Svkashyap * Redistribution and use in source and binary forms, with or without 7144966Svkashyap * modification, are permitted provided that the following conditions 8144966Svkashyap * are met: 9144966Svkashyap * 1. Redistributions of source code must retain the above copyright 10144966Svkashyap * notice, this list of conditions and the following disclaimer. 11144966Svkashyap * 2. Redistributions in binary form must reproduce the above copyright 12144966Svkashyap * notice, this list of conditions and the following disclaimer in the 13144966Svkashyap * documentation and/or other materials provided with the distribution. 14144966Svkashyap * 15144966Svkashyap * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16144966Svkashyap * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17144966Svkashyap * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18144966Svkashyap * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19144966Svkashyap * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20144966Svkashyap * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21144966Svkashyap * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22144966Svkashyap * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23144966Svkashyap * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24144966Svkashyap * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25144966Svkashyap * SUCH DAMAGE. 26144966Svkashyap * 27144966Svkashyap * $FreeBSD: releng/10.3/sys/dev/twa/tw_cl_intr.c 212008 2010-08-30 19:15:04Z delphij $ 28144966Svkashyap */ 29144966Svkashyap 30144966Svkashyap/* 31144966Svkashyap * AMCC'S 3ware driver for 9000 series storage controllers. 32144966Svkashyap * 33144966Svkashyap * Author: Vinod Kashyap 34169400Sscottl * Modifications by: Adam Radford 35172496Sscottl * Modifications by: Manjunath Ranganathaiah 36144966Svkashyap */ 37144966Svkashyap 38144966Svkashyap 39144966Svkashyap/* 40144966Svkashyap * Common Layer interrupt handling functions. 41144966Svkashyap */ 42144966Svkashyap 43144966Svkashyap 44144966Svkashyap#include "tw_osl_share.h" 45144966Svkashyap#include "tw_cl_share.h" 46144966Svkashyap#include "tw_cl_fwif.h" 47144966Svkashyap#include "tw_cl_ioctl.h" 48144966Svkashyap#include "tw_cl.h" 49144966Svkashyap#include "tw_cl_externs.h" 50144966Svkashyap#include "tw_osl_ioctl.h" 51144966Svkashyap 52144966Svkashyap 53144966Svkashyap 54144966Svkashyap/* 55144966Svkashyap * Function name: twa_interrupt 56144966Svkashyap * Description: Interrupt handler. Determines the kind of interrupt, 57144966Svkashyap * and returns TW_CL_TRUE if it recognizes the interrupt. 58144966Svkashyap * 59144966Svkashyap * Input: ctlr_handle -- controller handle 60144966Svkashyap * Output: None 61144966Svkashyap * Return value: TW_CL_TRUE -- interrupt recognized 62144966Svkashyap * TW_CL_FALSE-- interrupt not recognized 63144966Svkashyap */ 64144966SvkashyapTW_INT32 65144966Svkashyaptw_cl_interrupt(struct tw_cl_ctlr_handle *ctlr_handle) 66144966Svkashyap{ 67144966Svkashyap struct tw_cli_ctlr_context *ctlr = 68144966Svkashyap (struct tw_cli_ctlr_context *)(ctlr_handle->cl_ctlr_ctxt); 69144966Svkashyap TW_UINT32 status_reg; 70144966Svkashyap TW_INT32 rc = TW_CL_FALSE; 71144966Svkashyap 72144966Svkashyap tw_cli_dbg_printf(10, ctlr_handle, tw_osl_cur_func(), "entered"); 73144966Svkashyap 74169400Sscottl /* If we don't have controller context, bail */ 75169400Sscottl if (ctlr == NULL) 76169400Sscottl goto out; 77169400Sscottl 78144966Svkashyap /* 79208969Sdelphij * Bail If we get an interrupt while resetting, or shutting down. 80144966Svkashyap */ 81208969Sdelphij if (ctlr->reset_in_progress || !(ctlr->active)) 82208969Sdelphij goto out; 83144966Svkashyap 84144966Svkashyap /* Read the status register to determine the type of interrupt. */ 85144966Svkashyap status_reg = TW_CLI_READ_STATUS_REGISTER(ctlr_handle); 86144966Svkashyap if (tw_cli_check_ctlr_state(ctlr, status_reg)) 87208969Sdelphij goto out; 88144966Svkashyap 89144966Svkashyap /* Clear the interrupt. */ 90144966Svkashyap if (status_reg & TWA_STATUS_HOST_INTERRUPT) { 91144966Svkashyap tw_cli_dbg_printf(6, ctlr_handle, tw_osl_cur_func(), 92144966Svkashyap "Host interrupt"); 93144966Svkashyap TW_CLI_WRITE_CONTROL_REGISTER(ctlr_handle, 94144966Svkashyap TWA_CONTROL_CLEAR_HOST_INTERRUPT); 95144966Svkashyap } 96144966Svkashyap if (status_reg & TWA_STATUS_ATTENTION_INTERRUPT) { 97144966Svkashyap tw_cli_dbg_printf(6, ctlr_handle, tw_osl_cur_func(), 98144966Svkashyap "Attention interrupt"); 99208969Sdelphij rc |= TW_CL_TRUE; /* request for a deferred isr call */ 100208969Sdelphij tw_cli_process_attn_intr(ctlr); 101144966Svkashyap TW_CLI_WRITE_CONTROL_REGISTER(ctlr_handle, 102144966Svkashyap TWA_CONTROL_CLEAR_ATTENTION_INTERRUPT); 103144966Svkashyap } 104144966Svkashyap if (status_reg & TWA_STATUS_COMMAND_INTERRUPT) { 105144966Svkashyap tw_cli_dbg_printf(6, ctlr_handle, tw_osl_cur_func(), 106144966Svkashyap "Command interrupt"); 107144966Svkashyap rc |= TW_CL_TRUE; /* request for a deferred isr call */ 108208969Sdelphij tw_cli_process_cmd_intr(ctlr); 109208969Sdelphij if ((TW_CL_Q_FIRST_ITEM(&(ctlr->req_q_head[TW_CLI_PENDING_Q]))) == TW_CL_NULL) 110208969Sdelphij TW_CLI_WRITE_CONTROL_REGISTER(ctlr_handle, 111208969Sdelphij TWA_CONTROL_MASK_COMMAND_INTERRUPT); 112144966Svkashyap } 113144966Svkashyap if (status_reg & TWA_STATUS_RESPONSE_INTERRUPT) { 114144966Svkashyap tw_cli_dbg_printf(10, ctlr_handle, tw_osl_cur_func(), 115144966Svkashyap "Response interrupt"); 116144966Svkashyap rc |= TW_CL_TRUE; /* request for a deferred isr call */ 117208969Sdelphij tw_cli_process_resp_intr(ctlr); 118144966Svkashyap } 119169400Sscottlout: 120144966Svkashyap return(rc); 121144966Svkashyap} 122144966Svkashyap 123144966Svkashyap 124144966Svkashyap 125144966Svkashyap/* 126144966Svkashyap * Function name: tw_cli_process_host_intr 127144966Svkashyap * Description: This function gets called if we triggered an interrupt. 128144966Svkashyap * We don't use it as of now. 129144966Svkashyap * 130144966Svkashyap * Input: ctlr -- ptr to CL internal ctlr context 131144966Svkashyap * Output: None 132144966Svkashyap * Return value: None 133144966Svkashyap */ 134144966SvkashyapTW_VOID 135144966Svkashyaptw_cli_process_host_intr(struct tw_cli_ctlr_context *ctlr) 136144966Svkashyap{ 137144966Svkashyap tw_cli_dbg_printf(6, ctlr->ctlr_handle, tw_osl_cur_func(), "entered"); 138144966Svkashyap} 139144966Svkashyap 140144966Svkashyap 141144966Svkashyap 142144966Svkashyap/* 143144966Svkashyap * Function name: tw_cli_process_attn_intr 144144966Svkashyap * Description: This function gets called if the fw posted an AEN 145144966Svkashyap * (Asynchronous Event Notification). It fetches 146144966Svkashyap * all the AEN's that the fw might have posted. 147144966Svkashyap * 148144966Svkashyap * Input: ctlr -- ptr to CL internal ctlr context 149144966Svkashyap * Output: None 150144966Svkashyap * Return value: None 151144966Svkashyap */ 152144966SvkashyapTW_VOID 153144966Svkashyaptw_cli_process_attn_intr(struct tw_cli_ctlr_context *ctlr) 154144966Svkashyap{ 155144966Svkashyap TW_INT32 error; 156144966Svkashyap 157144966Svkashyap tw_cli_dbg_printf(6, ctlr->ctlr_handle, tw_osl_cur_func(), "entered"); 158144966Svkashyap 159144966Svkashyap if ((error = tw_cli_get_aen(ctlr))) { 160144966Svkashyap /* 161144966Svkashyap * If the driver is already in the process of retrieveing AEN's, 162144966Svkashyap * we will be returned TW_OSL_EBUSY. In this case, 163144966Svkashyap * tw_cli_param_callback or tw_cli_aen_callback will eventually 164144966Svkashyap * retrieve the AEN this attention interrupt is for. So, we 165144966Svkashyap * don't need to print the failure. 166144966Svkashyap */ 167144966Svkashyap if (error != TW_OSL_EBUSY) 168144966Svkashyap tw_cl_create_event(ctlr->ctlr_handle, TW_CL_FALSE, 169144966Svkashyap TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR, 170144966Svkashyap 0x1200, 0x1, TW_CL_SEVERITY_ERROR_STRING, 171144966Svkashyap "Failed to fetch AEN", 172144966Svkashyap "error = %d", error); 173144966Svkashyap } 174144966Svkashyap} 175144966Svkashyap 176144966Svkashyap 177144966Svkashyap 178144966Svkashyap/* 179144966Svkashyap * Function name: tw_cli_process_cmd_intr 180144966Svkashyap * Description: This function gets called if we hit a queue full 181144966Svkashyap * condition earlier, and the fw is now ready for 182144966Svkashyap * new cmds. Submits any pending requests. 183144966Svkashyap * 184144966Svkashyap * Input: ctlr -- ptr to CL internal ctlr context 185144966Svkashyap * Output: None 186144966Svkashyap * Return value: None 187144966Svkashyap */ 188144966SvkashyapTW_VOID 189144966Svkashyaptw_cli_process_cmd_intr(struct tw_cli_ctlr_context *ctlr) 190144966Svkashyap{ 191144966Svkashyap tw_cli_dbg_printf(6, ctlr->ctlr_handle, tw_osl_cur_func(), "entered"); 192144966Svkashyap 193144966Svkashyap /* Start any requests that might be in the pending queue. */ 194144966Svkashyap tw_cli_submit_pending_queue(ctlr); 195144966Svkashyap 196144966Svkashyap /* 197144966Svkashyap * If tw_cli_submit_pending_queue was unsuccessful due to a "cmd queue 198144966Svkashyap * full" condition, cmd_intr will already have been unmasked by 199144966Svkashyap * tw_cli_submit_cmd. We don't need to do it again... simply return. 200144966Svkashyap */ 201144966Svkashyap} 202144966Svkashyap 203144966Svkashyap 204144966Svkashyap 205144966Svkashyap/* 206144966Svkashyap * Function name: tw_cli_process_resp_intr 207144966Svkashyap * Description: Looks for cmd completions from fw; queues cmds completed 208144966Svkashyap * by fw into complete queue. 209144966Svkashyap * 210144966Svkashyap * Input: ctlr -- ptr to CL internal ctlr context 211144966Svkashyap * Output: None 212144966Svkashyap * Return value: 0 -- no ctlr error 213144966Svkashyap * non-zero-- ctlr error 214144966Svkashyap */ 215144966SvkashyapTW_INT32 216144966Svkashyaptw_cli_process_resp_intr(struct tw_cli_ctlr_context *ctlr) 217144966Svkashyap{ 218144966Svkashyap TW_UINT32 resp; 219144966Svkashyap struct tw_cli_req_context *req; 220144966Svkashyap TW_INT32 error; 221144966Svkashyap TW_UINT32 status_reg; 222144966Svkashyap 223144966Svkashyap tw_cli_dbg_printf(10, ctlr->ctlr_handle, tw_osl_cur_func(), "entered"); 224144966Svkashyap 225144966Svkashyap for (;;) { 226144966Svkashyap status_reg = TW_CLI_READ_STATUS_REGISTER(ctlr->ctlr_handle); 227144966Svkashyap if ((error = tw_cli_check_ctlr_state(ctlr, status_reg))) 228144966Svkashyap break; 229144966Svkashyap if (status_reg & TWA_STATUS_RESPONSE_QUEUE_EMPTY) { 230144966Svkashyap tw_cli_dbg_printf(7, ctlr->ctlr_handle, 231144966Svkashyap tw_osl_cur_func(), "Response queue empty"); 232144966Svkashyap break; 233144966Svkashyap } 234144966Svkashyap 235144966Svkashyap /* Response queue is not empty. */ 236144966Svkashyap resp = TW_CLI_READ_RESPONSE_QUEUE(ctlr->ctlr_handle); 237144966Svkashyap { 238144966Svkashyap req = &(ctlr->req_ctxt_buf[GET_RESP_ID(resp)]); 239144966Svkashyap } 240144966Svkashyap 241144966Svkashyap if (req->state != TW_CLI_REQ_STATE_BUSY) { 242144966Svkashyap tw_cl_create_event(ctlr->ctlr_handle, TW_CL_FALSE, 243144966Svkashyap TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR, 244144966Svkashyap 0x1201, 0x1, TW_CL_SEVERITY_ERROR_STRING, 245144966Svkashyap "Unposted command completed!!", 246144966Svkashyap "request = %p, status = %d", 247144966Svkashyap req, req->state); 248144966Svkashyap#ifdef TW_OSL_DEBUG 249144966Svkashyap tw_cl_print_ctlr_stats(ctlr->ctlr_handle); 250144966Svkashyap#endif /* TW_OSL_DEBUG */ 251212008Sdelphij continue; 252144966Svkashyap } 253144966Svkashyap 254144966Svkashyap /* 255144966Svkashyap * Remove the request from the busy queue, mark it as complete, 256144966Svkashyap * and enqueue it in the complete queue. 257144966Svkashyap */ 258144966Svkashyap tw_cli_req_q_remove_item(req, TW_CLI_BUSY_Q); 259144966Svkashyap req->state = TW_CLI_REQ_STATE_COMPLETE; 260144966Svkashyap tw_cli_req_q_insert_tail(req, TW_CLI_COMPLETE_Q); 261152213Svkashyap 262144966Svkashyap } 263144966Svkashyap 264144966Svkashyap /* Complete this, and other requests in the complete queue. */ 265144966Svkashyap tw_cli_process_complete_queue(ctlr); 266144966Svkashyap 267144966Svkashyap return(error); 268144966Svkashyap} 269144966Svkashyap 270144966Svkashyap 271144966Svkashyap 272144966Svkashyap/* 273144966Svkashyap * Function name: tw_cli_submit_pending_queue 274144966Svkashyap * Description: Kick starts any requests in the pending queue. 275144966Svkashyap * 276144966Svkashyap * Input: ctlr -- ptr to CL internal ctlr context 277144966Svkashyap * Output: None 278144966Svkashyap * Return value: 0 -- all pending requests submitted successfully 279144966Svkashyap * non-zero-- otherwise 280144966Svkashyap */ 281144966SvkashyapTW_INT32 282144966Svkashyaptw_cli_submit_pending_queue(struct tw_cli_ctlr_context *ctlr) 283144966Svkashyap{ 284144966Svkashyap struct tw_cli_req_context *req; 285144966Svkashyap TW_INT32 error = TW_OSL_ESUCCESS; 286144966Svkashyap 287144966Svkashyap tw_cli_dbg_printf(3, ctlr->ctlr_handle, tw_osl_cur_func(), "entered"); 288144966Svkashyap 289144966Svkashyap /* 290144966Svkashyap * Pull requests off the pending queue, and submit them. 291144966Svkashyap */ 292144966Svkashyap while ((req = tw_cli_req_q_remove_head(ctlr, TW_CLI_PENDING_Q)) != 293144966Svkashyap TW_CL_NULL) { 294144966Svkashyap if ((error = tw_cli_submit_cmd(req))) { 295144966Svkashyap if (error == TW_OSL_EBUSY) { 296144966Svkashyap tw_cli_dbg_printf(2, ctlr->ctlr_handle, 297144966Svkashyap tw_osl_cur_func(), 298144966Svkashyap "Requeueing pending request"); 299144966Svkashyap req->state = TW_CLI_REQ_STATE_PENDING; 300144966Svkashyap /* 301144966Svkashyap * Queue the request at the head of the pending 302144966Svkashyap * queue, and break away, so we don't try to 303144966Svkashyap * submit any more requests. 304144966Svkashyap */ 305144966Svkashyap tw_cli_req_q_insert_head(req, TW_CLI_PENDING_Q); 306144966Svkashyap break; 307144966Svkashyap } else { 308144966Svkashyap tw_cl_create_event(ctlr->ctlr_handle, 309144966Svkashyap TW_CL_FALSE, 310144966Svkashyap TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR, 311144966Svkashyap 0x1202, 0x1, 312144966Svkashyap TW_CL_SEVERITY_ERROR_STRING, 313144966Svkashyap "Could not start request " 314144966Svkashyap "in pending queue", 315144966Svkashyap "request = %p, opcode = 0x%x, " 316144966Svkashyap "error = %d", req, 317144966Svkashyap GET_OPCODE(req->cmd_pkt-> 318144966Svkashyap command.cmd_pkt_9k.res__opcode), 319144966Svkashyap error); 320144966Svkashyap /* 321144966Svkashyap * Set the appropriate error and call the CL 322144966Svkashyap * internal callback if there's one. If the 323144966Svkashyap * request originator is polling for completion, 324144966Svkashyap * he should be checking req->error to 325144966Svkashyap * determine that the request did not go 326144966Svkashyap * through. The request originators are 327144966Svkashyap * responsible for the clean-up. 328144966Svkashyap */ 329144966Svkashyap req->error_code = error; 330144966Svkashyap req->state = TW_CLI_REQ_STATE_COMPLETE; 331144966Svkashyap if (req->tw_cli_callback) 332144966Svkashyap req->tw_cli_callback(req); 333144966Svkashyap error = TW_OSL_ESUCCESS; 334144966Svkashyap } 335144966Svkashyap } 336144966Svkashyap } 337144966Svkashyap return(error); 338144966Svkashyap} 339144966Svkashyap 340144966Svkashyap 341144966Svkashyap 342144966Svkashyap/* 343144966Svkashyap * Function name: tw_cli_process_complete_queue 344144966Svkashyap * Description: Calls the CL internal callback routine, if any, for 345144966Svkashyap * each request in the complete queue. 346144966Svkashyap * 347144966Svkashyap * Input: ctlr -- ptr to CL internal ctlr context 348144966Svkashyap * Output: None 349144966Svkashyap * Return value: None 350144966Svkashyap */ 351144966SvkashyapTW_VOID 352144966Svkashyaptw_cli_process_complete_queue(struct tw_cli_ctlr_context *ctlr) 353144966Svkashyap{ 354144966Svkashyap struct tw_cli_req_context *req; 355144966Svkashyap 356144966Svkashyap tw_cli_dbg_printf(10, ctlr->ctlr_handle, tw_osl_cur_func(), "entered"); 357144966Svkashyap 358144966Svkashyap /* 359144966Svkashyap * Pull commands off the completed list, dispatch them appropriately. 360144966Svkashyap */ 361144966Svkashyap while ((req = tw_cli_req_q_remove_head(ctlr, TW_CLI_COMPLETE_Q)) != 362144966Svkashyap TW_CL_NULL) { 363144966Svkashyap /* Call the CL internal callback, if there's one. */ 364144966Svkashyap if (req->tw_cli_callback) 365144966Svkashyap req->tw_cli_callback(req); 366144966Svkashyap } 367144966Svkashyap} 368144966Svkashyap 369144966Svkashyap 370144966Svkashyap 371144966Svkashyap/* 372144966Svkashyap * Function name: tw_cli_complete_io 373144966Svkashyap * Description: CL internal callback for SCSI/fw passthru requests. 374144966Svkashyap * 375144966Svkashyap * Input: req -- ptr to CL internal request context 376144966Svkashyap * Output: None 377144966Svkashyap * Return value: None 378144966Svkashyap */ 379144966SvkashyapTW_VOID 380144966Svkashyaptw_cli_complete_io(struct tw_cli_req_context *req) 381144966Svkashyap{ 382144966Svkashyap struct tw_cli_ctlr_context *ctlr = req->ctlr; 383144966Svkashyap struct tw_cl_req_packet *req_pkt = 384144966Svkashyap (struct tw_cl_req_packet *)(req->orig_req); 385144966Svkashyap 386144966Svkashyap tw_cli_dbg_printf(8, ctlr->ctlr_handle, tw_osl_cur_func(), "entered"); 387144966Svkashyap 388144966Svkashyap req_pkt->status = TW_CL_ERR_REQ_SUCCESS; 389144966Svkashyap if (req->error_code) { 390144966Svkashyap req_pkt->status = TW_CL_ERR_REQ_UNABLE_TO_SUBMIT_COMMAND; 391144966Svkashyap goto out; 392144966Svkashyap } 393144966Svkashyap 394144966Svkashyap if (req->state != TW_CLI_REQ_STATE_COMPLETE) { 395144966Svkashyap tw_cl_create_event(ctlr->ctlr_handle, TW_CL_FALSE, 396144966Svkashyap TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR, 397144966Svkashyap 0x1203, 0x1, TW_CL_SEVERITY_ERROR_STRING, 398144966Svkashyap "I/O completion on incomplete command!!", 399144966Svkashyap "request = %p, status = %d", 400144966Svkashyap req, req->state); 401144966Svkashyap#ifdef TW_OSL_DEBUG 402144966Svkashyap tw_cl_print_ctlr_stats(ctlr->ctlr_handle); 403144966Svkashyap#endif /* TW_OSL_DEBUG */ 404212008Sdelphij return; 405144966Svkashyap } 406144966Svkashyap 407144966Svkashyap if (req->flags & TW_CLI_REQ_FLAGS_PASSTHRU) { 408144966Svkashyap /* Copy the command packet back into OSL's space. */ 409144966Svkashyap tw_osl_memcpy(req_pkt->gen_req_pkt.pt_req.cmd_pkt, req->cmd_pkt, 410144966Svkashyap sizeof(struct tw_cl_command_packet)); 411144966Svkashyap } else 412144966Svkashyap tw_cli_scsi_complete(req); 413144966Svkashyap 414144966Svkashyapout: 415144966Svkashyap req_pkt->tw_osl_callback(req->req_handle); 416144966Svkashyap tw_cli_req_q_insert_tail(req, TW_CLI_FREE_Q); 417144966Svkashyap} 418144966Svkashyap 419144966Svkashyap 420144966Svkashyap 421144966Svkashyap/* 422144966Svkashyap * Function name: tw_cli_scsi_complete 423144966Svkashyap * Description: Completion routine for SCSI requests. 424144966Svkashyap * 425144966Svkashyap * Input: req -- ptr to CL internal request context 426144966Svkashyap * Output: None 427144966Svkashyap * Return value: None 428144966Svkashyap */ 429144966SvkashyapTW_VOID 430144966Svkashyaptw_cli_scsi_complete(struct tw_cli_req_context *req) 431144966Svkashyap{ 432144966Svkashyap struct tw_cl_req_packet *req_pkt = 433144966Svkashyap (struct tw_cl_req_packet *)(req->orig_req); 434144966Svkashyap struct tw_cl_scsi_req_packet *scsi_req = 435144966Svkashyap &(req_pkt->gen_req_pkt.scsi_req); 436144966Svkashyap struct tw_cl_command_9k *cmd = 437144966Svkashyap &(req->cmd_pkt->command.cmd_pkt_9k); 438144966Svkashyap struct tw_cl_command_header *cmd_hdr; 439144966Svkashyap TW_UINT16 error; 440144966Svkashyap TW_UINT8 *cdb; 441144966Svkashyap 442144966Svkashyap tw_cli_dbg_printf(8, req->ctlr->ctlr_handle, tw_osl_cur_func(), 443144966Svkashyap "entered"); 444144966Svkashyap 445144966Svkashyap scsi_req->scsi_status = cmd->status; 446144966Svkashyap if (! cmd->status) 447144966Svkashyap return; 448144966Svkashyap 449144966Svkashyap tw_cli_dbg_printf(1, req->ctlr->ctlr_handle, tw_osl_cur_func(), 450144966Svkashyap "req_id = 0x%x, status = 0x%x", 451144966Svkashyap GET_REQ_ID(cmd->lun_l4__req_id), cmd->status); 452144966Svkashyap 453144966Svkashyap cmd_hdr = &(req->cmd_pkt->cmd_hdr); 454144966Svkashyap error = cmd_hdr->status_block.error; 455144966Svkashyap if ((error == TWA_ERROR_LOGICAL_UNIT_NOT_SUPPORTED) || 456144966Svkashyap (error == TWA_ERROR_UNIT_OFFLINE)) { 457144966Svkashyap if (GET_LUN_L4(cmd->lun_l4__req_id)) 458144966Svkashyap req_pkt->status |= TW_CL_ERR_REQ_INVALID_LUN; 459144966Svkashyap else 460144966Svkashyap req_pkt->status |= TW_CL_ERR_REQ_INVALID_TARGET; 461144966Svkashyap } else { 462144966Svkashyap tw_cli_dbg_printf(2, req->ctlr->ctlr_handle, 463144966Svkashyap tw_osl_cur_func(), 464144966Svkashyap "cmd = %x %x %x %x %x %x %x", 465144966Svkashyap GET_OPCODE(cmd->res__opcode), 466144966Svkashyap GET_SGL_OFF(cmd->res__opcode), 467144966Svkashyap cmd->unit, 468144966Svkashyap cmd->lun_l4__req_id, 469144966Svkashyap cmd->status, 470144966Svkashyap cmd->sgl_offset, 471144966Svkashyap cmd->lun_h4__sgl_entries); 472144966Svkashyap 473144966Svkashyap cdb = (TW_UINT8 *)(cmd->cdb); 474144966Svkashyap tw_cli_dbg_printf(2, req->ctlr->ctlr_handle, 475144966Svkashyap tw_osl_cur_func(), 476144966Svkashyap "cdb = %x %x %x %x %x %x %x %x " 477144966Svkashyap "%x %x %x %x %x %x %x %x", 478144966Svkashyap cdb[0], cdb[1], cdb[2], cdb[3], 479144966Svkashyap cdb[4], cdb[5], cdb[6], cdb[7], 480144966Svkashyap cdb[8], cdb[9], cdb[10], cdb[11], 481144966Svkashyap cdb[12], cdb[13], cdb[14], cdb[15]); 482144966Svkashyap 483212008Sdelphij#if 0 484144966Svkashyap /* 485144966Svkashyap * Print the error. Firmware doesn't yet support 486144966Svkashyap * the 'Mode Sense' cmd. Don't print if the cmd 487144966Svkashyap * is 'Mode Sense', and the error is 'Invalid field 488144966Svkashyap * in CDB'. 489144966Svkashyap */ 490144966Svkashyap if (! ((cdb[0] == 0x1A) && (error == 0x10D))) 491144966Svkashyap tw_cli_create_ctlr_event(req->ctlr, 492144966Svkashyap TW_CL_MESSAGE_SOURCE_CONTROLLER_ERROR, 493144966Svkashyap cmd_hdr); 494212008Sdelphij#endif // 0 495144966Svkashyap } 496144966Svkashyap 497144966Svkashyap if (scsi_req->sense_data) { 498144966Svkashyap tw_osl_memcpy(scsi_req->sense_data, cmd_hdr->sense_data, 499144966Svkashyap TWA_SENSE_DATA_LENGTH); 500144966Svkashyap scsi_req->sense_len = TWA_SENSE_DATA_LENGTH; 501144966Svkashyap req_pkt->status |= TW_CL_ERR_REQ_AUTO_SENSE_VALID; 502144966Svkashyap } 503144966Svkashyap req_pkt->status |= TW_CL_ERR_REQ_SCSI_ERROR; 504144966Svkashyap} 505144966Svkashyap 506144966Svkashyap 507144966Svkashyap 508144966Svkashyap/* 509144966Svkashyap * Function name: tw_cli_param_callback 510144966Svkashyap * Description: Callback for get/set_param requests. 511144966Svkashyap * 512144966Svkashyap * Input: req -- ptr to completed request pkt 513144966Svkashyap * Output: None 514144966Svkashyap * Return value: None 515144966Svkashyap */ 516144966SvkashyapTW_VOID 517144966Svkashyaptw_cli_param_callback(struct tw_cli_req_context *req) 518144966Svkashyap{ 519144966Svkashyap struct tw_cli_ctlr_context *ctlr = req->ctlr; 520144966Svkashyap union tw_cl_command_7k *cmd = 521144966Svkashyap &(req->cmd_pkt->command.cmd_pkt_7k); 522144966Svkashyap TW_INT32 error; 523144966Svkashyap 524144966Svkashyap tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(), "entered"); 525144966Svkashyap 526144966Svkashyap /* 527144966Svkashyap * If the request was never submitted to the controller, the function 528144966Svkashyap * that sets req->error is responsible for calling tw_cl_create_event. 529144966Svkashyap */ 530144966Svkashyap if (! req->error_code) 531144966Svkashyap if (cmd->param.status) { 532212008Sdelphij#if 0 533144966Svkashyap tw_cli_create_ctlr_event(ctlr, 534144966Svkashyap TW_CL_MESSAGE_SOURCE_CONTROLLER_ERROR, 535144966Svkashyap &(req->cmd_pkt->cmd_hdr)); 536212008Sdelphij#endif // 0 537144966Svkashyap tw_cl_create_event(ctlr->ctlr_handle, TW_CL_FALSE, 538144966Svkashyap TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR, 539144966Svkashyap 0x1204, 0x1, TW_CL_SEVERITY_ERROR_STRING, 540144966Svkashyap "get/set_param failed", 541144966Svkashyap "status = %d", cmd->param.status); 542144966Svkashyap } 543144966Svkashyap 544208969Sdelphij ctlr->internal_req_busy = TW_CL_FALSE; 545144966Svkashyap tw_cli_req_q_insert_tail(req, TW_CLI_FREE_Q); 546144966Svkashyap 547208969Sdelphij if ((ctlr->get_more_aens) && (!(ctlr->reset_in_progress))) { 548208969Sdelphij ctlr->get_more_aens = TW_CL_FALSE; 549144966Svkashyap tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(), 550144966Svkashyap "Fetching more AEN's"); 551144966Svkashyap if ((error = tw_cli_get_aen(ctlr))) 552144966Svkashyap tw_cl_create_event(ctlr->ctlr_handle, TW_CL_FALSE, 553144966Svkashyap TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR, 554144966Svkashyap 0x1205, 0x1, TW_CL_SEVERITY_ERROR_STRING, 555144966Svkashyap "Failed to fetch all AEN's from param_callback", 556144966Svkashyap "error = %d", error); 557144966Svkashyap } 558144966Svkashyap} 559144966Svkashyap 560144966Svkashyap 561144966Svkashyap 562144966Svkashyap/* 563144966Svkashyap * Function name: tw_cli_aen_callback 564144966Svkashyap * Description: Callback for requests to fetch AEN's. 565144966Svkashyap * 566144966Svkashyap * Input: req -- ptr to completed request pkt 567144966Svkashyap * Output: None 568144966Svkashyap * Return value: None 569144966Svkashyap */ 570144966SvkashyapTW_VOID 571144966Svkashyaptw_cli_aen_callback(struct tw_cli_req_context *req) 572144966Svkashyap{ 573144966Svkashyap struct tw_cli_ctlr_context *ctlr = req->ctlr; 574144966Svkashyap struct tw_cl_command_header *cmd_hdr; 575144966Svkashyap struct tw_cl_command_9k *cmd = 576144966Svkashyap &(req->cmd_pkt->command.cmd_pkt_9k); 577144966Svkashyap TW_UINT16 aen_code = TWA_AEN_QUEUE_EMPTY; 578144966Svkashyap TW_INT32 error; 579144966Svkashyap 580144966Svkashyap tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(), "entered"); 581144966Svkashyap 582144966Svkashyap tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(), 583144966Svkashyap "req_id = 0x%x, req error = %d, status = 0x%x", 584144966Svkashyap GET_REQ_ID(cmd->lun_l4__req_id), req->error_code, cmd->status); 585144966Svkashyap 586144966Svkashyap /* 587144966Svkashyap * If the request was never submitted to the controller, the function 588144966Svkashyap * that sets error is responsible for calling tw_cl_create_event. 589144966Svkashyap */ 590144966Svkashyap if (!(error = req->error_code)) 591144966Svkashyap if ((error = cmd->status)) { 592144966Svkashyap cmd_hdr = (struct tw_cl_command_header *) 593144966Svkashyap (&(req->cmd_pkt->cmd_hdr)); 594212008Sdelphij#if 0 595144966Svkashyap tw_cli_create_ctlr_event(ctlr, 596144966Svkashyap TW_CL_MESSAGE_SOURCE_CONTROLLER_ERROR, 597144966Svkashyap cmd_hdr); 598212008Sdelphij#endif // 0 599144966Svkashyap tw_cl_create_event(ctlr->ctlr_handle, TW_CL_FALSE, 600144966Svkashyap TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR, 601144966Svkashyap 0x1206, 0x1, TW_CL_SEVERITY_ERROR_STRING, 602144966Svkashyap "Request Sense failed", 603144966Svkashyap "opcode = 0x%x, status = %d", 604144966Svkashyap GET_OPCODE(cmd->res__opcode), cmd->status); 605144966Svkashyap } 606144966Svkashyap 607144966Svkashyap if (error) { 608208969Sdelphij ctlr->internal_req_busy = TW_CL_FALSE; 609144966Svkashyap tw_cli_req_q_insert_tail(req, TW_CLI_FREE_Q); 610144966Svkashyap return; 611144966Svkashyap } 612144966Svkashyap 613144966Svkashyap tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(), 614144966Svkashyap "Request Sense command succeeded"); 615144966Svkashyap 616144966Svkashyap aen_code = tw_cli_manage_aen(ctlr, req); 617144966Svkashyap 618144966Svkashyap if (aen_code != TWA_AEN_SYNC_TIME_WITH_HOST) { 619208969Sdelphij ctlr->internal_req_busy = TW_CL_FALSE; 620144966Svkashyap tw_cli_req_q_insert_tail(req, TW_CLI_FREE_Q); 621144966Svkashyap if (aen_code != TWA_AEN_QUEUE_EMPTY) 622144966Svkashyap if ((error = tw_cli_get_aen(ctlr))) 623144966Svkashyap tw_cl_create_event(ctlr->ctlr_handle, 624144966Svkashyap TW_CL_FALSE, 625144966Svkashyap TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR, 626144966Svkashyap 0x1207, 0x1, 627144966Svkashyap TW_CL_SEVERITY_ERROR_STRING, 628144966Svkashyap "Failed to fetch all AEN's", 629144966Svkashyap "error = %d", error); 630144966Svkashyap } 631144966Svkashyap} 632144966Svkashyap 633144966Svkashyap 634144966Svkashyap 635144966Svkashyap/* 636144966Svkashyap * Function name: tw_cli_manage_aen 637144966Svkashyap * Description: Handles AEN's. 638144966Svkashyap * 639144966Svkashyap * Input: ctlr -- ptr to CL internal ctlr context 640144966Svkashyap * req -- ptr to CL internal request context 641144966Svkashyap * Output: None 642144966Svkashyap * Return value: None 643144966Svkashyap */ 644144966SvkashyapTW_UINT16 645144966Svkashyaptw_cli_manage_aen(struct tw_cli_ctlr_context *ctlr, 646144966Svkashyap struct tw_cli_req_context *req) 647144966Svkashyap{ 648144966Svkashyap struct tw_cl_command_header *cmd_hdr; 649144966Svkashyap TW_UINT16 aen_code; 650144966Svkashyap TW_TIME local_time; 651144966Svkashyap TW_TIME sync_time; 652144966Svkashyap TW_UINT32 error; 653144966Svkashyap 654144966Svkashyap tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(), "entered"); 655144966Svkashyap 656144966Svkashyap cmd_hdr = (struct tw_cl_command_header *)(req->data); 657144966Svkashyap aen_code = cmd_hdr->status_block.error; 658144966Svkashyap 659144966Svkashyap switch (aen_code) { 660144966Svkashyap case TWA_AEN_SYNC_TIME_WITH_HOST: 661144966Svkashyap tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(), 662144966Svkashyap "Received AEN_SYNC_TIME"); 663144966Svkashyap /* 664144966Svkashyap * Free the internal req pkt right here, since 665144966Svkashyap * tw_cli_set_param will need it. 666144966Svkashyap */ 667208969Sdelphij ctlr->internal_req_busy = TW_CL_FALSE; 668144966Svkashyap tw_cli_req_q_insert_tail(req, TW_CLI_FREE_Q); 669144966Svkashyap 670144966Svkashyap /* 671144966Svkashyap * We will use a callback in tw_cli_set_param only when 672144966Svkashyap * interrupts are enabled and we can expect our callback 673208969Sdelphij * to get called. Setting the get_more_aens 674144966Svkashyap * flag will make the callback continue to try to retrieve 675144966Svkashyap * more AEN's. 676144966Svkashyap */ 677208969Sdelphij if (ctlr->interrupts_enabled) 678208969Sdelphij ctlr->get_more_aens = TW_CL_TRUE; 679144966Svkashyap /* Calculate time (in seconds) since last Sunday 12.00 AM. */ 680144966Svkashyap local_time = tw_osl_get_local_time(); 681144966Svkashyap sync_time = (local_time - (3 * 86400)) % 604800; 682144966Svkashyap if ((error = tw_cli_set_param(ctlr, TWA_PARAM_TIME_TABLE, 683144966Svkashyap TWA_PARAM_TIME_SCHED_TIME, 4, 684144966Svkashyap &sync_time, 685208969Sdelphij (ctlr->interrupts_enabled) 686144966Svkashyap ? tw_cli_param_callback : TW_CL_NULL))) 687144966Svkashyap tw_cl_create_event(ctlr->ctlr_handle, TW_CL_FALSE, 688144966Svkashyap TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR, 689144966Svkashyap 0x1208, 0x1, TW_CL_SEVERITY_ERROR_STRING, 690144966Svkashyap "Unable to sync time with ctlr", 691144966Svkashyap "error = %d", error); 692144966Svkashyap 693144966Svkashyap break; 694144966Svkashyap 695144966Svkashyap 696144966Svkashyap case TWA_AEN_QUEUE_EMPTY: 697144966Svkashyap tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(), 698144966Svkashyap "AEN queue empty"); 699144966Svkashyap break; 700144966Svkashyap 701144966Svkashyap 702144966Svkashyap default: 703144966Svkashyap /* Queue the event. */ 704144966Svkashyap 705144966Svkashyap tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(), 706144966Svkashyap "Queueing AEN"); 707144966Svkashyap tw_cli_create_ctlr_event(ctlr, 708144966Svkashyap TW_CL_MESSAGE_SOURCE_CONTROLLER_EVENT, 709144966Svkashyap cmd_hdr); 710144966Svkashyap break; 711144966Svkashyap } /* switch */ 712144966Svkashyap return(aen_code); 713144966Svkashyap} 714144966Svkashyap 715144966Svkashyap 716144966Svkashyap 717144966Svkashyap/* 718144966Svkashyap * Function name: tw_cli_enable_interrupts 719144966Svkashyap * Description: Enables interrupts on the controller 720144966Svkashyap * 721144966Svkashyap * Input: ctlr -- ptr to CL internal ctlr context 722144966Svkashyap * Output: None 723144966Svkashyap * Return value: None 724144966Svkashyap */ 725144966SvkashyapTW_VOID 726144966Svkashyaptw_cli_enable_interrupts(struct tw_cli_ctlr_context *ctlr) 727144966Svkashyap{ 728144966Svkashyap tw_cli_dbg_printf(3, ctlr->ctlr_handle, tw_osl_cur_func(), "entered"); 729144966Svkashyap 730208969Sdelphij ctlr->interrupts_enabled = TW_CL_TRUE; 731144966Svkashyap TW_CLI_WRITE_CONTROL_REGISTER(ctlr->ctlr_handle, 732144966Svkashyap TWA_CONTROL_CLEAR_ATTENTION_INTERRUPT | 733144966Svkashyap TWA_CONTROL_UNMASK_RESPONSE_INTERRUPT | 734144966Svkashyap TWA_CONTROL_ENABLE_INTERRUPTS); 735144966Svkashyap} 736144966Svkashyap 737144966Svkashyap 738144966Svkashyap 739144966Svkashyap/* 740144966Svkashyap * Function name: twa_setup 741144966Svkashyap * Description: Disables interrupts on the controller 742144966Svkashyap * 743144966Svkashyap * Input: ctlr -- ptr to CL internal ctlr context 744144966Svkashyap * Output: None 745144966Svkashyap * Return value: None 746144966Svkashyap */ 747144966SvkashyapTW_VOID 748144966Svkashyaptw_cli_disable_interrupts(struct tw_cli_ctlr_context *ctlr) 749144966Svkashyap{ 750144966Svkashyap tw_cli_dbg_printf(3, ctlr->ctlr_handle, tw_osl_cur_func(), "entered"); 751144966Svkashyap 752144966Svkashyap TW_CLI_WRITE_CONTROL_REGISTER(ctlr->ctlr_handle, 753144966Svkashyap TWA_CONTROL_DISABLE_INTERRUPTS); 754208969Sdelphij ctlr->interrupts_enabled = TW_CL_FALSE; 755144966Svkashyap} 756144966Svkashyap 757