tw_cl_io.c revision 330897
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: stable/11/sys/dev/twa/tw_cl_io.c 330897 2018-03-14 03:19:51Z eadler $ 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/* 42 * Common Layer I/O functions. 43 */ 44 45 46#include "tw_osl_share.h" 47#include "tw_cl_share.h" 48#include "tw_cl_fwif.h" 49#include "tw_cl_ioctl.h" 50#include "tw_cl.h" 51#include "tw_cl_externs.h" 52#include "tw_osl_ioctl.h" 53 54#include <cam/cam.h> 55#include <cam/cam_ccb.h> 56#include <cam/cam_xpt_sim.h> 57 58 59 60/* 61 * Function name: tw_cl_start_io 62 * Description: Interface to OS Layer for accepting SCSI requests. 63 * 64 * Input: ctlr_handle -- controller handle 65 * req_pkt -- OSL built request packet 66 * req_handle -- request handle 67 * Output: None 68 * Return value: 0 -- success 69 * non-zero-- failure 70 */ 71TW_INT32 72tw_cl_start_io(struct tw_cl_ctlr_handle *ctlr_handle, 73 struct tw_cl_req_packet *req_pkt, struct tw_cl_req_handle *req_handle) 74{ 75 struct tw_cli_ctlr_context *ctlr; 76 struct tw_cli_req_context *req; 77 struct tw_cl_command_9k *cmd; 78 struct tw_cl_scsi_req_packet *scsi_req; 79 TW_INT32 error = TW_CL_ERR_REQ_SUCCESS; 80 81 tw_cli_dbg_printf(10, ctlr_handle, tw_osl_cur_func(), "entered"); 82 83 ctlr = (struct tw_cli_ctlr_context *)(ctlr_handle->cl_ctlr_ctxt); 84 85 /* 86 * If working with a firmware version that does not support multiple 87 * luns, and this request is directed at a non-zero lun, error it 88 * back right away. 89 */ 90 if ((req_pkt->gen_req_pkt.scsi_req.lun) && 91 (ctlr->working_srl < TWA_MULTI_LUN_FW_SRL)) { 92 req_pkt->status |= (TW_CL_ERR_REQ_INVALID_LUN | 93 TW_CL_ERR_REQ_SCSI_ERROR); 94 req_pkt->tw_osl_callback(req_handle); 95 return(TW_CL_ERR_REQ_SUCCESS); 96 } 97 98 if ((req = tw_cli_get_request(ctlr 99 )) == TW_CL_NULL) { 100 tw_cli_dbg_printf(2, ctlr_handle, tw_osl_cur_func(), 101 "Out of request context packets: returning busy"); 102 return(TW_OSL_EBUSY); 103 } 104 105 req_handle->cl_req_ctxt = req; 106 req->req_handle = req_handle; 107 req->orig_req = req_pkt; 108 req->tw_cli_callback = tw_cli_complete_io; 109 110 req->flags |= TW_CLI_REQ_FLAGS_EXTERNAL; 111 req->flags |= TW_CLI_REQ_FLAGS_9K; 112 113 scsi_req = &(req_pkt->gen_req_pkt.scsi_req); 114 115 /* Build the cmd pkt. */ 116 cmd = &(req->cmd_pkt->command.cmd_pkt_9k); 117 118 req->cmd_pkt->cmd_hdr.header_desc.size_header = 128; 119 120 cmd->res__opcode = BUILD_RES__OPCODE(0, TWA_FW_CMD_EXECUTE_SCSI); 121 cmd->unit = (TW_UINT8)(scsi_req->unit); 122 cmd->lun_l4__req_id = TW_CL_SWAP16( 123 BUILD_LUN_L4__REQ_ID(scsi_req->lun, req->request_id)); 124 cmd->status = 0; 125 cmd->sgl_offset = 16; /* offset from end of hdr = max cdb len */ 126 tw_osl_memcpy(cmd->cdb, scsi_req->cdb, scsi_req->cdb_len); 127 128 if (req_pkt->flags & TW_CL_REQ_CALLBACK_FOR_SGLIST) { 129 TW_UINT32 num_sgl_entries; 130 131 req_pkt->tw_osl_sgl_callback(req_handle, cmd->sg_list, 132 &num_sgl_entries); 133 cmd->lun_h4__sgl_entries = 134 TW_CL_SWAP16(BUILD_LUN_H4__SGL_ENTRIES(scsi_req->lun, 135 num_sgl_entries)); 136 } else { 137 cmd->lun_h4__sgl_entries = 138 TW_CL_SWAP16(BUILD_LUN_H4__SGL_ENTRIES(scsi_req->lun, 139 scsi_req->sgl_entries)); 140 tw_cli_fill_sg_list(ctlr, scsi_req->sg_list, 141 cmd->sg_list, scsi_req->sgl_entries); 142 } 143 144 if (((TW_CL_Q_FIRST_ITEM(&(ctlr->req_q_head[TW_CLI_PENDING_Q]))) != TW_CL_NULL) || 145 (ctlr->reset_in_progress)) { 146 tw_cli_req_q_insert_tail(req, TW_CLI_PENDING_Q); 147 TW_CLI_WRITE_CONTROL_REGISTER(ctlr_handle, 148 TWA_CONTROL_UNMASK_COMMAND_INTERRUPT); 149 } else if ((error = tw_cli_submit_cmd(req))) { 150 tw_cli_dbg_printf(2, ctlr_handle, tw_osl_cur_func(), 151 "Could not start request. request = %p, error = %d", 152 req, error); 153 tw_cli_req_q_insert_tail(req, TW_CLI_FREE_Q); 154 } 155 return(error); 156} 157 158 159 160/* 161 * Function name: tw_cli_submit_cmd 162 * Description: Submits a cmd to firmware. 163 * 164 * Input: req -- ptr to CL internal request context 165 * Output: None 166 * Return value: 0 -- success 167 * non-zero-- failure 168 */ 169TW_INT32 170tw_cli_submit_cmd(struct tw_cli_req_context *req) 171{ 172 struct tw_cli_ctlr_context *ctlr = req->ctlr; 173 struct tw_cl_ctlr_handle *ctlr_handle = ctlr->ctlr_handle; 174 TW_UINT32 status_reg; 175 TW_INT32 error = 0; 176 177 tw_cli_dbg_printf(10, ctlr_handle, tw_osl_cur_func(), "entered"); 178 179 /* Serialize access to the controller cmd queue. */ 180 tw_osl_get_lock(ctlr_handle, ctlr->io_lock); 181 182 /* For 9650SE first write low 4 bytes */ 183 if ((ctlr->device_id == TW_CL_DEVICE_ID_9K_E) || 184 (ctlr->device_id == TW_CL_DEVICE_ID_9K_SA)) 185 tw_osl_write_reg(ctlr_handle, 186 TWA_COMMAND_QUEUE_OFFSET_LOW, 187 (TW_UINT32)(req->cmd_pkt_phys + sizeof(struct tw_cl_command_header)), 4); 188 189 status_reg = TW_CLI_READ_STATUS_REGISTER(ctlr_handle); 190 if (status_reg & TWA_STATUS_COMMAND_QUEUE_FULL) { 191 struct tw_cl_req_packet *req_pkt = 192 (struct tw_cl_req_packet *)(req->orig_req); 193 194 tw_cli_dbg_printf(7, ctlr_handle, tw_osl_cur_func(), 195 "Cmd queue full"); 196 197 if ((req->flags & TW_CLI_REQ_FLAGS_INTERNAL) 198 || ((req_pkt) && 199 (req_pkt->flags & TW_CL_REQ_RETRY_ON_BUSY)) 200 ) { 201 if (req->state != TW_CLI_REQ_STATE_PENDING) { 202 tw_cli_dbg_printf(2, ctlr_handle, 203 tw_osl_cur_func(), 204 "pending internal/ioctl request"); 205 req->state = TW_CLI_REQ_STATE_PENDING; 206 tw_cli_req_q_insert_tail(req, TW_CLI_PENDING_Q); 207 /* Unmask command interrupt. */ 208 TW_CLI_WRITE_CONTROL_REGISTER(ctlr_handle, 209 TWA_CONTROL_UNMASK_COMMAND_INTERRUPT); 210 } else 211 error = TW_OSL_EBUSY; 212 } else { 213 error = TW_OSL_EBUSY; 214 } 215 } else { 216 tw_cli_dbg_printf(10, ctlr_handle, tw_osl_cur_func(), 217 "Submitting command"); 218 219 /* Insert command into busy queue */ 220 req->state = TW_CLI_REQ_STATE_BUSY; 221 tw_cli_req_q_insert_tail(req, TW_CLI_BUSY_Q); 222 223 if ((ctlr->device_id == TW_CL_DEVICE_ID_9K_E) || 224 (ctlr->device_id == TW_CL_DEVICE_ID_9K_SA)) { 225 /* Now write the high 4 bytes */ 226 tw_osl_write_reg(ctlr_handle, 227 TWA_COMMAND_QUEUE_OFFSET_HIGH, 228 (TW_UINT32)(((TW_UINT64)(req->cmd_pkt_phys + sizeof(struct tw_cl_command_header)))>>32), 4); 229 } else { 230 if (ctlr->flags & TW_CL_64BIT_ADDRESSES) { 231 /* First write the low 4 bytes, then the high 4. */ 232 tw_osl_write_reg(ctlr_handle, 233 TWA_COMMAND_QUEUE_OFFSET_LOW, 234 (TW_UINT32)(req->cmd_pkt_phys + sizeof(struct tw_cl_command_header)), 4); 235 tw_osl_write_reg(ctlr_handle, 236 TWA_COMMAND_QUEUE_OFFSET_HIGH, 237 (TW_UINT32)(((TW_UINT64)(req->cmd_pkt_phys + sizeof(struct tw_cl_command_header)))>>32), 4); 238 } else 239 tw_osl_write_reg(ctlr_handle, 240 TWA_COMMAND_QUEUE_OFFSET, 241 (TW_UINT32)(req->cmd_pkt_phys + sizeof(struct tw_cl_command_header)), 4); 242 } 243 } 244 245 tw_osl_free_lock(ctlr_handle, ctlr->io_lock); 246 247 return(error); 248} 249 250 251 252/* 253 * Function name: tw_cl_fw_passthru 254 * Description: Interface to OS Layer for accepting firmware 255 * passthru requests. 256 * Input: ctlr_handle -- controller handle 257 * req_pkt -- OSL built request packet 258 * req_handle -- request handle 259 * Output: None 260 * Return value: 0 -- success 261 * non-zero-- failure 262 */ 263TW_INT32 264tw_cl_fw_passthru(struct tw_cl_ctlr_handle *ctlr_handle, 265 struct tw_cl_req_packet *req_pkt, struct tw_cl_req_handle *req_handle) 266{ 267 struct tw_cli_ctlr_context *ctlr; 268 struct tw_cli_req_context *req; 269 union tw_cl_command_7k *cmd_7k; 270 struct tw_cl_command_9k *cmd_9k; 271 struct tw_cl_passthru_req_packet *pt_req; 272 TW_UINT8 opcode; 273 TW_UINT8 sgl_offset; 274 TW_VOID *sgl = TW_CL_NULL; 275 TW_INT32 error = TW_CL_ERR_REQ_SUCCESS; 276 277 tw_cli_dbg_printf(5, ctlr_handle, tw_osl_cur_func(), "entered"); 278 279 ctlr = (struct tw_cli_ctlr_context *)(ctlr_handle->cl_ctlr_ctxt); 280 281 if ((req = tw_cli_get_request(ctlr 282 )) == TW_CL_NULL) { 283 tw_cli_dbg_printf(2, ctlr_handle, tw_osl_cur_func(), 284 "Out of request context packets: returning busy"); 285 return(TW_OSL_EBUSY); 286 } 287 288 req_handle->cl_req_ctxt = req; 289 req->req_handle = req_handle; 290 req->orig_req = req_pkt; 291 req->tw_cli_callback = tw_cli_complete_io; 292 293 req->flags |= TW_CLI_REQ_FLAGS_PASSTHRU; 294 295 pt_req = &(req_pkt->gen_req_pkt.pt_req); 296 297 tw_osl_memcpy(req->cmd_pkt, pt_req->cmd_pkt, 298 pt_req->cmd_pkt_length); 299 /* Build the cmd pkt. */ 300 if ((opcode = GET_OPCODE(((TW_UINT8 *) 301 (pt_req->cmd_pkt))[sizeof(struct tw_cl_command_header)])) 302 == TWA_FW_CMD_EXECUTE_SCSI) { 303 TW_UINT16 lun_l4, lun_h4; 304 305 tw_cli_dbg_printf(5, ctlr_handle, tw_osl_cur_func(), 306 "passthru: 9k cmd pkt"); 307 req->flags |= TW_CLI_REQ_FLAGS_9K; 308 cmd_9k = &(req->cmd_pkt->command.cmd_pkt_9k); 309 lun_l4 = GET_LUN_L4(cmd_9k->lun_l4__req_id); 310 lun_h4 = GET_LUN_H4(cmd_9k->lun_h4__sgl_entries); 311 cmd_9k->lun_l4__req_id = TW_CL_SWAP16( 312 BUILD_LUN_L4__REQ_ID(lun_l4, req->request_id)); 313 if (pt_req->sgl_entries) { 314 cmd_9k->lun_h4__sgl_entries = 315 TW_CL_SWAP16(BUILD_LUN_H4__SGL_ENTRIES(lun_h4, 316 pt_req->sgl_entries)); 317 sgl = (TW_VOID *)(cmd_9k->sg_list); 318 } 319 } else { 320 tw_cli_dbg_printf(5, ctlr_handle, tw_osl_cur_func(), 321 "passthru: 7k cmd pkt"); 322 cmd_7k = &(req->cmd_pkt->command.cmd_pkt_7k); 323 cmd_7k->generic.request_id = 324 (TW_UINT8)(TW_CL_SWAP16(req->request_id)); 325 if ((sgl_offset = 326 GET_SGL_OFF(cmd_7k->generic.sgl_off__opcode))) { 327 if (ctlr->device_id == TW_CL_DEVICE_ID_9K_SA) 328 sgl = (((TW_UINT32 *)cmd_7k) + cmd_7k->generic.size); 329 else 330 sgl = (((TW_UINT32 *)cmd_7k) + sgl_offset); 331 cmd_7k->generic.size += pt_req->sgl_entries * 332 ((ctlr->flags & TW_CL_64BIT_ADDRESSES) ? 3 : 2); 333 } 334 } 335 336 if (sgl) 337 tw_cli_fill_sg_list(ctlr, pt_req->sg_list, 338 sgl, pt_req->sgl_entries); 339 340 if (((TW_CL_Q_FIRST_ITEM(&(ctlr->req_q_head[TW_CLI_PENDING_Q]))) != TW_CL_NULL) || 341 (ctlr->reset_in_progress)) { 342 tw_cli_req_q_insert_tail(req, TW_CLI_PENDING_Q); 343 TW_CLI_WRITE_CONTROL_REGISTER(ctlr_handle, 344 TWA_CONTROL_UNMASK_COMMAND_INTERRUPT); 345 } else if ((error = tw_cli_submit_cmd(req))) { 346 tw_cl_create_event(ctlr_handle, TW_CL_FALSE, 347 TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR, 348 0x1100, 0x1, TW_CL_SEVERITY_ERROR_STRING, 349 "Failed to start passthru command", 350 "error = %d", error); 351 tw_cli_req_q_insert_tail(req, TW_CLI_FREE_Q); 352 } 353 return(error); 354} 355 356 357 358/* 359 * Function name: tw_cl_ioctl 360 * Description: Handler of CL supported ioctl cmds. 361 * 362 * Input: ctlr -- ptr to per ctlr structure 363 * cmd -- ioctl cmd 364 * buf -- ptr to buffer in kernel memory, which is 365 * a copy of the input buffer in user-space 366 * Output: buf -- ptr to buffer in kernel memory, which will 367 * need to be copied to the output buffer in 368 * user-space 369 * Return value: 0 -- success 370 * non-zero-- failure 371 */ 372TW_INT32 373tw_cl_ioctl(struct tw_cl_ctlr_handle *ctlr_handle, u_long cmd, TW_VOID *buf) 374{ 375 struct tw_cli_ctlr_context *ctlr = 376 (struct tw_cli_ctlr_context *)(ctlr_handle->cl_ctlr_ctxt); 377 struct tw_cl_ioctl_packet *user_buf = 378 (struct tw_cl_ioctl_packet *)buf; 379 struct tw_cl_event_packet event_buf; 380 TW_INT32 event_index; 381 TW_INT32 start_index; 382 TW_INT32 error = TW_OSL_ESUCCESS; 383 384 tw_cli_dbg_printf(5, ctlr_handle, tw_osl_cur_func(), "entered"); 385 386 /* Serialize access to the AEN queue and the ioctl lock. */ 387 tw_osl_get_lock(ctlr_handle, ctlr->gen_lock); 388 389 switch (cmd) { 390 case TW_CL_IOCTL_GET_FIRST_EVENT: 391 tw_cli_dbg_printf(3, ctlr_handle, tw_osl_cur_func(), 392 "Get First Event"); 393 394 if (ctlr->aen_q_wrapped) { 395 if (ctlr->aen_q_overflow) { 396 /* 397 * The aen queue has wrapped, even before some 398 * events have been retrieved. Let the caller 399 * know that he missed out on some AEN's. 400 */ 401 user_buf->driver_pkt.status = 402 TW_CL_ERROR_AEN_OVERFLOW; 403 ctlr->aen_q_overflow = TW_CL_FALSE; 404 } else 405 user_buf->driver_pkt.status = 0; 406 event_index = ctlr->aen_head; 407 } else { 408 if (ctlr->aen_head == ctlr->aen_tail) { 409 user_buf->driver_pkt.status = 410 TW_CL_ERROR_AEN_NO_EVENTS; 411 break; 412 } 413 user_buf->driver_pkt.status = 0; 414 event_index = ctlr->aen_tail; /* = 0 */ 415 } 416 tw_osl_memcpy(user_buf->data_buf, 417 &(ctlr->aen_queue[event_index]), 418 sizeof(struct tw_cl_event_packet)); 419 420 ctlr->aen_queue[event_index].retrieved = TW_CL_AEN_RETRIEVED; 421 422 break; 423 424 425 case TW_CL_IOCTL_GET_LAST_EVENT: 426 tw_cli_dbg_printf(3, ctlr_handle, tw_osl_cur_func(), 427 "Get Last Event"); 428 429 if (ctlr->aen_q_wrapped) { 430 if (ctlr->aen_q_overflow) { 431 /* 432 * The aen queue has wrapped, even before some 433 * events have been retrieved. Let the caller 434 * know that he missed out on some AEN's. 435 */ 436 user_buf->driver_pkt.status = 437 TW_CL_ERROR_AEN_OVERFLOW; 438 ctlr->aen_q_overflow = TW_CL_FALSE; 439 } else 440 user_buf->driver_pkt.status = 0; 441 } else { 442 if (ctlr->aen_head == ctlr->aen_tail) { 443 user_buf->driver_pkt.status = 444 TW_CL_ERROR_AEN_NO_EVENTS; 445 break; 446 } 447 user_buf->driver_pkt.status = 0; 448 } 449 event_index = (ctlr->aen_head - 1 + ctlr->max_aens_supported) % 450 ctlr->max_aens_supported; 451 452 tw_osl_memcpy(user_buf->data_buf, 453 &(ctlr->aen_queue[event_index]), 454 sizeof(struct tw_cl_event_packet)); 455 456 ctlr->aen_queue[event_index].retrieved = TW_CL_AEN_RETRIEVED; 457 458 break; 459 460 461 case TW_CL_IOCTL_GET_NEXT_EVENT: 462 tw_cli_dbg_printf(3, ctlr_handle, tw_osl_cur_func(), 463 "Get Next Event"); 464 465 user_buf->driver_pkt.status = 0; 466 if (ctlr->aen_q_wrapped) { 467 tw_cli_dbg_printf(3, ctlr_handle, tw_osl_cur_func(), 468 "Get Next Event: wrapped"); 469 if (ctlr->aen_q_overflow) { 470 /* 471 * The aen queue has wrapped, even before some 472 * events have been retrieved. Let the caller 473 * know that he missed out on some AEN's. 474 */ 475 tw_cli_dbg_printf(2, ctlr_handle, 476 tw_osl_cur_func(), 477 "Get Next Event: overflow"); 478 user_buf->driver_pkt.status = 479 TW_CL_ERROR_AEN_OVERFLOW; 480 ctlr->aen_q_overflow = TW_CL_FALSE; 481 } 482 start_index = ctlr->aen_head; 483 } else { 484 if (ctlr->aen_head == ctlr->aen_tail) { 485 tw_cli_dbg_printf(3, ctlr_handle, 486 tw_osl_cur_func(), 487 "Get Next Event: empty queue"); 488 user_buf->driver_pkt.status = 489 TW_CL_ERROR_AEN_NO_EVENTS; 490 break; 491 } 492 start_index = ctlr->aen_tail; /* = 0 */ 493 } 494 tw_osl_memcpy(&event_buf, user_buf->data_buf, 495 sizeof(struct tw_cl_event_packet)); 496 497 event_index = (start_index + event_buf.sequence_id - 498 ctlr->aen_queue[start_index].sequence_id + 1) % 499 ctlr->max_aens_supported; 500 501 tw_cli_dbg_printf(3, ctlr_handle, tw_osl_cur_func(), 502 "Get Next Event: si = %x, ei = %x, ebsi = %x, " 503 "sisi = %x, eisi = %x", 504 start_index, event_index, event_buf.sequence_id, 505 ctlr->aen_queue[start_index].sequence_id, 506 ctlr->aen_queue[event_index].sequence_id); 507 508 if (! (ctlr->aen_queue[event_index].sequence_id > 509 event_buf.sequence_id)) { 510 /* 511 * We don't have any event matching the criterion. So, 512 * we have to report TW_CL_ERROR_NO_EVENTS. If we also 513 * encountered an overflow condition above, we cannot 514 * report both conditions during this call. We choose 515 * to report NO_EVENTS this time, and an overflow the 516 * next time we are called. 517 */ 518 if (user_buf->driver_pkt.status == 519 TW_CL_ERROR_AEN_OVERFLOW) { 520 /* 521 * Make a note so we report the overflow 522 * next time. 523 */ 524 ctlr->aen_q_overflow = TW_CL_TRUE; 525 } 526 user_buf->driver_pkt.status = TW_CL_ERROR_AEN_NO_EVENTS; 527 break; 528 } 529 /* Copy the event -- even if there has been an overflow. */ 530 tw_osl_memcpy(user_buf->data_buf, 531 &(ctlr->aen_queue[event_index]), 532 sizeof(struct tw_cl_event_packet)); 533 534 ctlr->aen_queue[event_index].retrieved = TW_CL_AEN_RETRIEVED; 535 536 break; 537 538 539 case TW_CL_IOCTL_GET_PREVIOUS_EVENT: 540 tw_cli_dbg_printf(3, ctlr_handle, tw_osl_cur_func(), 541 "Get Previous Event"); 542 543 user_buf->driver_pkt.status = 0; 544 if (ctlr->aen_q_wrapped) { 545 if (ctlr->aen_q_overflow) { 546 /* 547 * The aen queue has wrapped, even before some 548 * events have been retrieved. Let the caller 549 * know that he missed out on some AEN's. 550 */ 551 user_buf->driver_pkt.status = 552 TW_CL_ERROR_AEN_OVERFLOW; 553 ctlr->aen_q_overflow = TW_CL_FALSE; 554 } 555 start_index = ctlr->aen_head; 556 } else { 557 if (ctlr->aen_head == ctlr->aen_tail) { 558 user_buf->driver_pkt.status = 559 TW_CL_ERROR_AEN_NO_EVENTS; 560 break; 561 } 562 start_index = ctlr->aen_tail; /* = 0 */ 563 } 564 tw_osl_memcpy(&event_buf, user_buf->data_buf, 565 sizeof(struct tw_cl_event_packet)); 566 567 event_index = (start_index + event_buf.sequence_id - 568 ctlr->aen_queue[start_index].sequence_id - 1) % 569 ctlr->max_aens_supported; 570 571 if (! (ctlr->aen_queue[event_index].sequence_id < 572 event_buf.sequence_id)) { 573 /* 574 * We don't have any event matching the criterion. So, 575 * we have to report TW_CL_ERROR_NO_EVENTS. If we also 576 * encountered an overflow condition above, we cannot 577 * report both conditions during this call. We choose 578 * to report NO_EVENTS this time, and an overflow the 579 * next time we are called. 580 */ 581 if (user_buf->driver_pkt.status == 582 TW_CL_ERROR_AEN_OVERFLOW) { 583 /* 584 * Make a note so we report the overflow 585 * next time. 586 */ 587 ctlr->aen_q_overflow = TW_CL_TRUE; 588 } 589 user_buf->driver_pkt.status = TW_CL_ERROR_AEN_NO_EVENTS; 590 break; 591 } 592 /* Copy the event -- even if there has been an overflow. */ 593 tw_osl_memcpy(user_buf->data_buf, 594 &(ctlr->aen_queue[event_index]), 595 sizeof(struct tw_cl_event_packet)); 596 597 ctlr->aen_queue[event_index].retrieved = TW_CL_AEN_RETRIEVED; 598 599 break; 600 601 602 case TW_CL_IOCTL_GET_LOCK: 603 { 604 struct tw_cl_lock_packet lock_pkt; 605 TW_TIME cur_time; 606 607 tw_cli_dbg_printf(3, ctlr_handle, tw_osl_cur_func(), 608 "Get ioctl lock"); 609 610 cur_time = tw_osl_get_local_time(); 611 tw_osl_memcpy(&lock_pkt, user_buf->data_buf, 612 sizeof(struct tw_cl_lock_packet)); 613 614 if ((ctlr->ioctl_lock.lock == TW_CLI_LOCK_FREE) || 615 (lock_pkt.force_flag) || 616 (cur_time >= ctlr->ioctl_lock.timeout)) { 617 tw_cli_dbg_printf(3, ctlr_handle, tw_osl_cur_func(), 618 "GET_LOCK: Getting lock!"); 619 ctlr->ioctl_lock.lock = TW_CLI_LOCK_HELD; 620 ctlr->ioctl_lock.timeout = 621 cur_time + (lock_pkt.timeout_msec / 1000); 622 lock_pkt.time_remaining_msec = lock_pkt.timeout_msec; 623 user_buf->driver_pkt.status = 0; 624 } else { 625 tw_cli_dbg_printf(2, ctlr_handle, tw_osl_cur_func(), 626 "GET_LOCK: Lock already held!"); 627 lock_pkt.time_remaining_msec = (TW_UINT32)( 628 (ctlr->ioctl_lock.timeout - cur_time) * 1000); 629 user_buf->driver_pkt.status = 630 TW_CL_ERROR_IOCTL_LOCK_ALREADY_HELD; 631 } 632 tw_osl_memcpy(user_buf->data_buf, &lock_pkt, 633 sizeof(struct tw_cl_lock_packet)); 634 break; 635 } 636 637 638 case TW_CL_IOCTL_RELEASE_LOCK: 639 tw_cli_dbg_printf(3, ctlr_handle, tw_osl_cur_func(), 640 "Release ioctl lock"); 641 642 if (ctlr->ioctl_lock.lock == TW_CLI_LOCK_FREE) { 643 tw_cli_dbg_printf(2, ctlr_handle, tw_osl_cur_func(), 644 "twa_ioctl: RELEASE_LOCK: Lock not held!"); 645 user_buf->driver_pkt.status = 646 TW_CL_ERROR_IOCTL_LOCK_NOT_HELD; 647 } else { 648 tw_cli_dbg_printf(3, ctlr_handle, tw_osl_cur_func(), 649 "RELEASE_LOCK: Releasing lock!"); 650 ctlr->ioctl_lock.lock = TW_CLI_LOCK_FREE; 651 user_buf->driver_pkt.status = 0; 652 } 653 break; 654 655 656 case TW_CL_IOCTL_GET_COMPATIBILITY_INFO: 657 { 658 struct tw_cl_compatibility_packet comp_pkt; 659 660 tw_cli_dbg_printf(3, ctlr_handle, tw_osl_cur_func(), 661 "Get compatibility info"); 662 663 tw_osl_memcpy(comp_pkt.driver_version, 664 TW_OSL_DRIVER_VERSION_STRING, 665 sizeof(TW_OSL_DRIVER_VERSION_STRING)); 666 comp_pkt.working_srl = ctlr->working_srl; 667 comp_pkt.working_branch = ctlr->working_branch; 668 comp_pkt.working_build = ctlr->working_build; 669 comp_pkt.driver_srl_high = TWA_CURRENT_FW_SRL; 670 comp_pkt.driver_branch_high = 671 TWA_CURRENT_FW_BRANCH(ctlr->arch_id); 672 comp_pkt.driver_build_high = 673 TWA_CURRENT_FW_BUILD(ctlr->arch_id); 674 comp_pkt.driver_srl_low = TWA_BASE_FW_SRL; 675 comp_pkt.driver_branch_low = TWA_BASE_FW_BRANCH; 676 comp_pkt.driver_build_low = TWA_BASE_FW_BUILD; 677 comp_pkt.fw_on_ctlr_srl = ctlr->fw_on_ctlr_srl; 678 comp_pkt.fw_on_ctlr_branch = ctlr->fw_on_ctlr_branch; 679 comp_pkt.fw_on_ctlr_build = ctlr->fw_on_ctlr_build; 680 user_buf->driver_pkt.status = 0; 681 682 /* Copy compatibility information to user space. */ 683 tw_osl_memcpy(user_buf->data_buf, &comp_pkt, 684 (sizeof(struct tw_cl_compatibility_packet) < 685 user_buf->driver_pkt.buffer_length) ? 686 sizeof(struct tw_cl_compatibility_packet) : 687 user_buf->driver_pkt.buffer_length); 688 break; 689 } 690 691 default: 692 /* Unknown opcode. */ 693 tw_cli_dbg_printf(3, ctlr_handle, tw_osl_cur_func(), 694 "Unknown ioctl cmd 0x%x", cmd); 695 error = TW_OSL_ENOTTY; 696 } 697 698 tw_osl_free_lock(ctlr_handle, ctlr->gen_lock); 699 return(error); 700} 701 702 703 704/* 705 * Function name: tw_cli_get_param 706 * Description: Get a firmware parameter. 707 * 708 * Input: ctlr -- ptr to per ctlr structure 709 * table_id -- parameter table # 710 * param_id -- index of the parameter in the table 711 * param_size -- size of the parameter in bytes 712 * callback -- ptr to function, if any, to be called 713 * back on completion; TW_CL_NULL if no callback. 714 * Output: param_data -- param value 715 * Return value: 0 -- success 716 * non-zero-- failure 717 */ 718TW_INT32 719tw_cli_get_param(struct tw_cli_ctlr_context *ctlr, TW_INT32 table_id, 720 TW_INT32 param_id, TW_VOID *param_data, TW_INT32 param_size, 721 TW_VOID (* callback)(struct tw_cli_req_context *req)) 722{ 723 struct tw_cli_req_context *req; 724 union tw_cl_command_7k *cmd; 725 struct tw_cl_param_9k *param = TW_CL_NULL; 726 TW_INT32 error = TW_OSL_EBUSY; 727 728 tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(), "entered"); 729 730 /* Get a request packet. */ 731 if ((req = tw_cli_get_request(ctlr 732 )) == TW_CL_NULL) 733 goto out; 734 735 /* Make sure this is the only CL internal request at this time. */ 736 if (ctlr->internal_req_busy) { 737 error = TW_OSL_EBUSY; 738 goto out; 739 } 740 ctlr->internal_req_busy = TW_CL_TRUE; 741 req->data = ctlr->internal_req_data; 742 req->data_phys = ctlr->internal_req_data_phys; 743 req->length = TW_CLI_SECTOR_SIZE; 744 req->flags |= TW_CLI_REQ_FLAGS_INTERNAL; 745 746 /* Initialize memory to read data into. */ 747 param = (struct tw_cl_param_9k *)(req->data); 748 tw_osl_memzero(param, sizeof(struct tw_cl_param_9k) - 1 + param_size); 749 750 /* Build the cmd pkt. */ 751 cmd = &(req->cmd_pkt->command.cmd_pkt_7k); 752 753 req->cmd_pkt->cmd_hdr.header_desc.size_header = 128; 754 755 cmd->param.sgl_off__opcode = 756 BUILD_SGL_OFF__OPCODE(2, TWA_FW_CMD_GET_PARAM); 757 cmd->param.request_id = (TW_UINT8)(TW_CL_SWAP16(req->request_id)); 758 cmd->param.host_id__unit = BUILD_HOST_ID__UNIT(0, 0); 759 cmd->param.param_count = TW_CL_SWAP16(1); 760 761 if (ctlr->flags & TW_CL_64BIT_ADDRESSES) { 762 ((struct tw_cl_sg_desc64 *)(cmd->param.sgl))[0].address = 763 TW_CL_SWAP64(req->data_phys); 764 ((struct tw_cl_sg_desc64 *)(cmd->param.sgl))[0].length = 765 TW_CL_SWAP32(req->length); 766 cmd->param.size = 2 + 3; 767 } else { 768 ((struct tw_cl_sg_desc32 *)(cmd->param.sgl))[0].address = 769 TW_CL_SWAP32(req->data_phys); 770 ((struct tw_cl_sg_desc32 *)(cmd->param.sgl))[0].length = 771 TW_CL_SWAP32(req->length); 772 cmd->param.size = 2 + 2; 773 } 774 775 /* Specify which parameter we need. */ 776 param->table_id = TW_CL_SWAP16(table_id | TWA_9K_PARAM_DESCRIPTOR); 777 param->parameter_id = (TW_UINT8)(param_id); 778 param->parameter_size_bytes = TW_CL_SWAP16(param_size); 779 780 /* Submit the command. */ 781 if (callback == TW_CL_NULL) { 782 /* There's no call back; wait till the command completes. */ 783 error = tw_cli_submit_and_poll_request(req, 784 TW_CLI_REQUEST_TIMEOUT_PERIOD); 785 if (error) 786 goto out; 787 if ((error = cmd->param.status)) { 788#if 0 789 tw_cli_create_ctlr_event(ctlr, 790 TW_CL_MESSAGE_SOURCE_CONTROLLER_ERROR, 791 &(req->cmd_pkt->cmd_hdr)); 792#endif // 0 793 goto out; 794 } 795 tw_osl_memcpy(param_data, param->data, param_size); 796 ctlr->internal_req_busy = TW_CL_FALSE; 797 tw_cli_req_q_insert_tail(req, TW_CLI_FREE_Q); 798 } else { 799 /* There's a call back. Simply submit the command. */ 800 req->tw_cli_callback = callback; 801 if ((error = tw_cli_submit_cmd(req))) 802 goto out; 803 } 804 return(0); 805 806out: 807 tw_cl_create_event(ctlr->ctlr_handle, TW_CL_FALSE, 808 TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR, 809 0x1101, 0x1, TW_CL_SEVERITY_ERROR_STRING, 810 "get_param failed", 811 "error = %d", error); 812 if (param) 813 ctlr->internal_req_busy = TW_CL_FALSE; 814 if (req) 815 tw_cli_req_q_insert_tail(req, TW_CLI_FREE_Q); 816 return(1); 817} 818 819 820 821/* 822 * Function name: tw_cli_set_param 823 * Description: Set a firmware parameter. 824 * 825 * Input: ctlr -- ptr to per ctlr structure 826 * table_id -- parameter table # 827 * param_id -- index of the parameter in the table 828 * param_size -- size of the parameter in bytes 829 * callback -- ptr to function, if any, to be called 830 * back on completion; TW_CL_NULL if no callback. 831 * Output: None 832 * Return value: 0 -- success 833 * non-zero-- failure 834 */ 835TW_INT32 836tw_cli_set_param(struct tw_cli_ctlr_context *ctlr, TW_INT32 table_id, 837 TW_INT32 param_id, TW_INT32 param_size, TW_VOID *data, 838 TW_VOID (* callback)(struct tw_cli_req_context *req)) 839{ 840 struct tw_cli_req_context *req; 841 union tw_cl_command_7k *cmd; 842 struct tw_cl_param_9k *param = TW_CL_NULL; 843 TW_INT32 error = TW_OSL_EBUSY; 844 845 tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(), "entered"); 846 847 /* Get a request packet. */ 848 if ((req = tw_cli_get_request(ctlr 849 )) == TW_CL_NULL) 850 goto out; 851 852 /* Make sure this is the only CL internal request at this time. */ 853 if (ctlr->internal_req_busy) { 854 error = TW_OSL_EBUSY; 855 goto out; 856 } 857 ctlr->internal_req_busy = TW_CL_TRUE; 858 req->data = ctlr->internal_req_data; 859 req->data_phys = ctlr->internal_req_data_phys; 860 req->length = TW_CLI_SECTOR_SIZE; 861 req->flags |= TW_CLI_REQ_FLAGS_INTERNAL; 862 863 /* Initialize memory to send data using. */ 864 param = (struct tw_cl_param_9k *)(req->data); 865 tw_osl_memzero(param, sizeof(struct tw_cl_param_9k) - 1 + param_size); 866 867 /* Build the cmd pkt. */ 868 cmd = &(req->cmd_pkt->command.cmd_pkt_7k); 869 870 req->cmd_pkt->cmd_hdr.header_desc.size_header = 128; 871 872 cmd->param.sgl_off__opcode = 873 BUILD_SGL_OFF__OPCODE(2, TWA_FW_CMD_SET_PARAM); 874 cmd->param.request_id = (TW_UINT8)(TW_CL_SWAP16(req->request_id)); 875 cmd->param.host_id__unit = BUILD_HOST_ID__UNIT(0, 0); 876 cmd->param.param_count = TW_CL_SWAP16(1); 877 878 if (ctlr->flags & TW_CL_64BIT_ADDRESSES) { 879 ((struct tw_cl_sg_desc64 *)(cmd->param.sgl))[0].address = 880 TW_CL_SWAP64(req->data_phys); 881 ((struct tw_cl_sg_desc64 *)(cmd->param.sgl))[0].length = 882 TW_CL_SWAP32(req->length); 883 cmd->param.size = 2 + 3; 884 } else { 885 ((struct tw_cl_sg_desc32 *)(cmd->param.sgl))[0].address = 886 TW_CL_SWAP32(req->data_phys); 887 ((struct tw_cl_sg_desc32 *)(cmd->param.sgl))[0].length = 888 TW_CL_SWAP32(req->length); 889 cmd->param.size = 2 + 2; 890 } 891 892 /* Specify which parameter we want to set. */ 893 param->table_id = TW_CL_SWAP16(table_id | TWA_9K_PARAM_DESCRIPTOR); 894 param->parameter_id = (TW_UINT8)(param_id); 895 param->parameter_size_bytes = TW_CL_SWAP16(param_size); 896 tw_osl_memcpy(param->data, data, param_size); 897 898 /* Submit the command. */ 899 if (callback == TW_CL_NULL) { 900 /* There's no call back; wait till the command completes. */ 901 error = tw_cli_submit_and_poll_request(req, 902 TW_CLI_REQUEST_TIMEOUT_PERIOD); 903 if (error) 904 goto out; 905 if ((error = cmd->param.status)) { 906#if 0 907 tw_cli_create_ctlr_event(ctlr, 908 TW_CL_MESSAGE_SOURCE_CONTROLLER_ERROR, 909 &(req->cmd_pkt->cmd_hdr)); 910#endif // 0 911 goto out; 912 } 913 ctlr->internal_req_busy = TW_CL_FALSE; 914 tw_cli_req_q_insert_tail(req, TW_CLI_FREE_Q); 915 } else { 916 /* There's a call back. Simply submit the command. */ 917 req->tw_cli_callback = callback; 918 if ((error = tw_cli_submit_cmd(req))) 919 goto out; 920 } 921 return(error); 922 923out: 924 tw_cl_create_event(ctlr->ctlr_handle, TW_CL_FALSE, 925 TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR, 926 0x1102, 0x1, TW_CL_SEVERITY_ERROR_STRING, 927 "set_param failed", 928 "error = %d", error); 929 if (param) 930 ctlr->internal_req_busy = TW_CL_FALSE; 931 if (req) 932 tw_cli_req_q_insert_tail(req, TW_CLI_FREE_Q); 933 return(error); 934} 935 936 937 938/* 939 * Function name: tw_cli_submit_and_poll_request 940 * Description: Sends down a firmware cmd, and waits for the completion 941 * in a tight loop. 942 * 943 * Input: req -- ptr to request pkt 944 * timeout -- max # of seconds to wait before giving up 945 * Output: None 946 * Return value: 0 -- success 947 * non-zero-- failure 948 */ 949TW_INT32 950tw_cli_submit_and_poll_request(struct tw_cli_req_context *req, 951 TW_UINT32 timeout) 952{ 953 struct tw_cli_ctlr_context *ctlr = req->ctlr; 954 TW_TIME end_time; 955 TW_INT32 error; 956 957 tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(), "entered"); 958 959 /* 960 * If the cmd queue is full, tw_cli_submit_cmd will queue this 961 * request in the pending queue, since this is an internal request. 962 */ 963 if ((error = tw_cli_submit_cmd(req))) { 964 tw_cl_create_event(ctlr->ctlr_handle, TW_CL_FALSE, 965 TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR, 966 0x1103, 0x1, TW_CL_SEVERITY_ERROR_STRING, 967 "Failed to start internal request", 968 "error = %d", error); 969 return(error); 970 } 971 972 /* 973 * Poll for the response until the command gets completed, or there's 974 * a timeout. 975 */ 976 end_time = tw_osl_get_local_time() + timeout; 977 do { 978 if ((error = req->error_code)) 979 /* 980 * This will take care of completion due to a reset, 981 * or a failure in tw_cli_submit_pending_queue. 982 * The caller should do the clean-up. 983 */ 984 return(error); 985 986 /* See if the command completed. */ 987 tw_cli_process_resp_intr(ctlr); 988 989 if ((req->state != TW_CLI_REQ_STATE_BUSY) && 990 (req->state != TW_CLI_REQ_STATE_PENDING)) 991 return(req->state != TW_CLI_REQ_STATE_COMPLETE); 992 } while (tw_osl_get_local_time() <= end_time); 993 994 /* Time out! */ 995 tw_cl_create_event(ctlr->ctlr_handle, TW_CL_FALSE, 996 TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR, 997 0x1104, 0x1, TW_CL_SEVERITY_ERROR_STRING, 998 "Internal request timed out", 999 "request = %p", req); 1000 1001 /* 1002 * We will reset the controller only if the request has already been 1003 * submitted, so as to not lose the request packet. If a busy request 1004 * timed out, the reset will take care of freeing resources. If a 1005 * pending request timed out, we will free resources for that request, 1006 * right here, thereby avoiding a reset. So, the caller is expected 1007 * to NOT cleanup when TW_OSL_ETIMEDOUT is returned. 1008 */ 1009 1010 /* 1011 * We have to make sure that this timed out request, if it were in the 1012 * pending queue, doesn't get submitted while we are here, from 1013 * tw_cli_submit_pending_queue. There could be a race in that case. 1014 * Need to revisit. 1015 */ 1016 if (req->state == TW_CLI_REQ_STATE_PENDING) { 1017 tw_cli_dbg_printf(3, ctlr->ctlr_handle, tw_osl_cur_func(), 1018 "Removing request from pending queue"); 1019 /* 1020 * Request was never submitted. Clean up. Note that we did 1021 * not do a reset. So, we have to remove the request ourselves 1022 * from the pending queue (as against tw_cli_drain_pendinq_queue 1023 * taking care of it). 1024 */ 1025 tw_cli_req_q_remove_item(req, TW_CLI_PENDING_Q); 1026 if ((TW_CL_Q_FIRST_ITEM(&(ctlr->req_q_head[TW_CLI_PENDING_Q]))) == TW_CL_NULL) 1027 TW_CLI_WRITE_CONTROL_REGISTER(ctlr->ctlr_handle, 1028 TWA_CONTROL_MASK_COMMAND_INTERRUPT); 1029 if (req->data) 1030 ctlr->internal_req_busy = TW_CL_FALSE; 1031 tw_cli_req_q_insert_tail(req, TW_CLI_FREE_Q); 1032 } 1033 1034 return(TW_OSL_ETIMEDOUT); 1035} 1036 1037 1038 1039/* 1040 * Function name: tw_cl_reset_ctlr 1041 * Description: Soft resets and then initializes the controller; 1042 * drains any incomplete requests. 1043 * 1044 * Input: ctlr -- ptr to per ctlr structure 1045 * req_handle -- ptr to request handle 1046 * Output: None 1047 * Return value: 0 -- success 1048 * non-zero-- failure 1049 */ 1050TW_INT32 1051tw_cl_reset_ctlr(struct tw_cl_ctlr_handle *ctlr_handle) 1052{ 1053 struct tw_cli_ctlr_context *ctlr = 1054 (struct tw_cli_ctlr_context *)(ctlr_handle->cl_ctlr_ctxt); 1055 struct twa_softc *sc = ctlr_handle->osl_ctlr_ctxt; 1056 struct tw_cli_req_context *req; 1057 TW_INT32 reset_attempt = 1; 1058 TW_INT32 error = 0; 1059 1060 tw_cli_dbg_printf(2, ctlr_handle, tw_osl_cur_func(), "entered"); 1061 1062 ctlr->reset_in_progress = TW_CL_TRUE; 1063 twa_teardown_intr(sc); 1064 1065 1066 /* 1067 * Error back all requests in the complete, busy, and pending queues. 1068 * If any request is already on its way to getting submitted, it's in 1069 * none of these queues and so, will not be completed. That request 1070 * will continue its course and get submitted to the controller after 1071 * the reset is done (and io_lock is released). 1072 */ 1073 tw_cli_drain_complete_queue(ctlr); 1074 tw_cli_drain_busy_queue(ctlr); 1075 tw_cli_drain_pending_queue(ctlr); 1076 ctlr->internal_req_busy = TW_CL_FALSE; 1077 ctlr->get_more_aens = TW_CL_FALSE; 1078 1079 /* Soft reset the controller. */ 1080 while (reset_attempt <= TW_CLI_MAX_RESET_ATTEMPTS) { 1081 if ((error = tw_cli_soft_reset(ctlr))) { 1082 tw_cl_create_event(ctlr_handle, TW_CL_FALSE, 1083 TW_CL_MESSAGE_SOURCE_COMMON_LAYER_EVENT, 1084 0x1105, 0x1, TW_CL_SEVERITY_ERROR_STRING, 1085 "Controller reset failed", 1086 "error = %d; attempt %d", error, reset_attempt++); 1087 reset_attempt++; 1088 continue; 1089 } 1090 1091 /* Re-establish logical connection with the controller. */ 1092 if ((error = tw_cli_init_connection(ctlr, 1093 (TW_UINT16)(ctlr->max_simult_reqs), 1094 0, 0, 0, 0, 0, TW_CL_NULL, TW_CL_NULL, TW_CL_NULL, 1095 TW_CL_NULL, TW_CL_NULL))) { 1096 tw_cl_create_event(ctlr_handle, TW_CL_FALSE, 1097 TW_CL_MESSAGE_SOURCE_COMMON_LAYER_EVENT, 1098 0x1106, 0x1, TW_CL_SEVERITY_ERROR_STRING, 1099 "Can't initialize connection after reset", 1100 "error = %d", error); 1101 reset_attempt++; 1102 continue; 1103 } 1104 1105#ifdef TW_OSL_DEBUG 1106 tw_cl_create_event(ctlr_handle, TW_CL_FALSE, 1107 TW_CL_MESSAGE_SOURCE_COMMON_LAYER_EVENT, 1108 0x1107, 0x3, TW_CL_SEVERITY_INFO_STRING, 1109 "Controller reset done!", " "); 1110#endif /* TW_OSL_DEBUG */ 1111 break; 1112 } /* End of while */ 1113 1114 /* Move commands from the reset queue to the pending queue. */ 1115 while ((req = tw_cli_req_q_remove_head(ctlr, TW_CLI_RESET_Q)) != TW_CL_NULL) { 1116 tw_osl_timeout(req->req_handle); 1117 tw_cli_req_q_insert_tail(req, TW_CLI_PENDING_Q); 1118 } 1119 1120 twa_setup_intr(sc); 1121 tw_cli_enable_interrupts(ctlr); 1122 if ((TW_CL_Q_FIRST_ITEM(&(ctlr->req_q_head[TW_CLI_PENDING_Q]))) != TW_CL_NULL) 1123 TW_CLI_WRITE_CONTROL_REGISTER(ctlr_handle, 1124 TWA_CONTROL_UNMASK_COMMAND_INTERRUPT); 1125 ctlr->reset_in_progress = TW_CL_FALSE; 1126 ctlr->reset_needed = TW_CL_FALSE; 1127 1128 /* Request for a bus re-scan. */ 1129 tw_osl_scan_bus(ctlr_handle); 1130 1131 return(error); 1132} 1133 1134TW_VOID 1135tw_cl_set_reset_needed(struct tw_cl_ctlr_handle *ctlr_handle) 1136{ 1137 struct tw_cli_ctlr_context *ctlr = 1138 (struct tw_cli_ctlr_context *)(ctlr_handle->cl_ctlr_ctxt); 1139 1140 ctlr->reset_needed = TW_CL_TRUE; 1141} 1142 1143TW_INT32 1144tw_cl_is_reset_needed(struct tw_cl_ctlr_handle *ctlr_handle) 1145{ 1146 struct tw_cli_ctlr_context *ctlr = 1147 (struct tw_cli_ctlr_context *)(ctlr_handle->cl_ctlr_ctxt); 1148 1149 return(ctlr->reset_needed); 1150} 1151 1152TW_INT32 1153tw_cl_is_active(struct tw_cl_ctlr_handle *ctlr_handle) 1154{ 1155 struct tw_cli_ctlr_context *ctlr = 1156 (struct tw_cli_ctlr_context *) 1157 (ctlr_handle->cl_ctlr_ctxt); 1158 1159 return(ctlr->active); 1160} 1161 1162 1163 1164/* 1165 * Function name: tw_cli_soft_reset 1166 * Description: Does the actual soft reset. 1167 * 1168 * Input: ctlr -- ptr to per ctlr structure 1169 * Output: None 1170 * Return value: 0 -- success 1171 * non-zero-- failure 1172 */ 1173TW_INT32 1174tw_cli_soft_reset(struct tw_cli_ctlr_context *ctlr) 1175{ 1176 struct tw_cl_ctlr_handle *ctlr_handle = ctlr->ctlr_handle; 1177 int found; 1178 int loop_count; 1179 TW_UINT32 error; 1180 1181 tw_cli_dbg_printf(1, ctlr_handle, tw_osl_cur_func(), "entered"); 1182 1183 tw_cl_create_event(ctlr_handle, TW_CL_FALSE, 1184 TW_CL_MESSAGE_SOURCE_COMMON_LAYER_EVENT, 1185 0x1108, 0x3, TW_CL_SEVERITY_INFO_STRING, 1186 "Resetting controller...", 1187 " "); 1188 1189 /* Don't let any new commands get submitted to the controller. */ 1190 tw_osl_get_lock(ctlr_handle, ctlr->io_lock); 1191 1192 TW_CLI_SOFT_RESET(ctlr_handle); 1193 1194 if ((ctlr->device_id == TW_CL_DEVICE_ID_9K_X) || 1195 (ctlr->device_id == TW_CL_DEVICE_ID_9K_E) || 1196 (ctlr->device_id == TW_CL_DEVICE_ID_9K_SA)) { 1197 /* 1198 * There's a hardware bug in the G133 ASIC, which can lead to 1199 * PCI parity errors and hangs, if the host accesses any 1200 * registers when the firmware is resetting the hardware, as 1201 * part of a hard/soft reset. The window of time when the 1202 * problem can occur is about 10 ms. Here, we will handshake 1203 * with the firmware to find out when the firmware is pulling 1204 * down the hardware reset pin, and wait for about 500 ms to 1205 * make sure we don't access any hardware registers (for 1206 * polling) during that window. 1207 */ 1208 ctlr->reset_phase1_in_progress = TW_CL_TRUE; 1209 loop_count = 0; 1210 do { 1211 found = (tw_cli_find_response(ctlr, TWA_RESET_PHASE1_NOTIFICATION_RESPONSE) == TW_OSL_ESUCCESS); 1212 tw_osl_delay(10); 1213 loop_count++; 1214 error = 0x7888; 1215 } while (!found && (loop_count < 6000000)); /* Loop for no more than 60 seconds */ 1216 1217 if (!found) { 1218 tw_cl_create_event(ctlr_handle, TW_CL_FALSE, 1219 TW_CL_MESSAGE_SOURCE_COMMON_LAYER_EVENT, 1220 0x1109, 0x1, TW_CL_SEVERITY_ERROR_STRING, 1221 "Missed firmware handshake after soft-reset", 1222 "error = %d", error); 1223 tw_osl_free_lock(ctlr_handle, ctlr->io_lock); 1224 return(error); 1225 } 1226 1227 tw_osl_delay(TWA_RESET_PHASE1_WAIT_TIME_MS * 1000); 1228 ctlr->reset_phase1_in_progress = TW_CL_FALSE; 1229 } 1230 1231 if ((error = tw_cli_poll_status(ctlr, 1232 TWA_STATUS_MICROCONTROLLER_READY | 1233 TWA_STATUS_ATTENTION_INTERRUPT, 1234 TW_CLI_RESET_TIMEOUT_PERIOD))) { 1235 tw_cl_create_event(ctlr_handle, TW_CL_FALSE, 1236 TW_CL_MESSAGE_SOURCE_COMMON_LAYER_EVENT, 1237 0x1109, 0x1, TW_CL_SEVERITY_ERROR_STRING, 1238 "Micro-ctlr not ready/No attn intr after reset", 1239 "error = %d", error); 1240 tw_osl_free_lock(ctlr_handle, ctlr->io_lock); 1241 return(error); 1242 } 1243 1244 TW_CLI_WRITE_CONTROL_REGISTER(ctlr_handle, 1245 TWA_CONTROL_CLEAR_ATTENTION_INTERRUPT); 1246 1247 if ((error = tw_cli_drain_response_queue(ctlr))) { 1248 tw_cl_create_event(ctlr_handle, TW_CL_FALSE, 1249 TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR, 1250 0x110A, 0x1, TW_CL_SEVERITY_ERROR_STRING, 1251 "Can't drain response queue after reset", 1252 "error = %d", error); 1253 tw_osl_free_lock(ctlr_handle, ctlr->io_lock); 1254 return(error); 1255 } 1256 1257 tw_osl_free_lock(ctlr_handle, ctlr->io_lock); 1258 1259 if ((error = tw_cli_drain_aen_queue(ctlr))) { 1260 tw_cl_create_event(ctlr_handle, TW_CL_FALSE, 1261 TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR, 1262 0x110B, 0x1, TW_CL_SEVERITY_ERROR_STRING, 1263 "Can't drain AEN queue after reset", 1264 "error = %d", error); 1265 return(error); 1266 } 1267 1268 if ((error = tw_cli_find_aen(ctlr, TWA_AEN_SOFT_RESET))) { 1269 tw_cl_create_event(ctlr_handle, TW_CL_FALSE, 1270 TW_CL_MESSAGE_SOURCE_COMMON_LAYER_EVENT, 1271 0x110C, 0x1, TW_CL_SEVERITY_ERROR_STRING, 1272 "Reset not reported by controller", 1273 "error = %d", error); 1274 return(error); 1275 } 1276 1277 return(TW_OSL_ESUCCESS); 1278} 1279 1280 1281 1282/* 1283 * Function name: tw_cli_send_scsi_cmd 1284 * Description: Sends down a scsi cmd to fw. 1285 * 1286 * Input: req -- ptr to request pkt 1287 * cmd -- opcode of scsi cmd to send 1288 * Output: None 1289 * Return value: 0 -- success 1290 * non-zero-- failure 1291 */ 1292TW_INT32 1293tw_cli_send_scsi_cmd(struct tw_cli_req_context *req, TW_INT32 cmd) 1294{ 1295 struct tw_cl_command_packet *cmdpkt; 1296 struct tw_cl_command_9k *cmd9k; 1297 struct tw_cli_ctlr_context *ctlr; 1298 TW_INT32 error; 1299 1300 ctlr = req->ctlr; 1301 tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(), "entered"); 1302 1303 /* Make sure this is the only CL internal request at this time. */ 1304 if (ctlr->internal_req_busy) 1305 return(TW_OSL_EBUSY); 1306 ctlr->internal_req_busy = TW_CL_TRUE; 1307 req->data = ctlr->internal_req_data; 1308 req->data_phys = ctlr->internal_req_data_phys; 1309 tw_osl_memzero(req->data, TW_CLI_SECTOR_SIZE); 1310 req->length = TW_CLI_SECTOR_SIZE; 1311 1312 /* Build the cmd pkt. */ 1313 cmdpkt = req->cmd_pkt; 1314 1315 cmdpkt->cmd_hdr.header_desc.size_header = 128; 1316 1317 cmd9k = &(cmdpkt->command.cmd_pkt_9k); 1318 1319 cmd9k->res__opcode = 1320 BUILD_RES__OPCODE(0, TWA_FW_CMD_EXECUTE_SCSI); 1321 cmd9k->unit = 0; 1322 cmd9k->lun_l4__req_id = TW_CL_SWAP16(req->request_id); 1323 cmd9k->status = 0; 1324 cmd9k->sgl_offset = 16; /* offset from end of hdr = max cdb len */ 1325 cmd9k->lun_h4__sgl_entries = TW_CL_SWAP16(1); 1326 1327 if (req->ctlr->flags & TW_CL_64BIT_ADDRESSES) { 1328 ((struct tw_cl_sg_desc64 *)(cmd9k->sg_list))[0].address = 1329 TW_CL_SWAP64(req->data_phys); 1330 ((struct tw_cl_sg_desc64 *)(cmd9k->sg_list))[0].length = 1331 TW_CL_SWAP32(req->length); 1332 } else { 1333 ((struct tw_cl_sg_desc32 *)(cmd9k->sg_list))[0].address = 1334 TW_CL_SWAP32(req->data_phys); 1335 ((struct tw_cl_sg_desc32 *)(cmd9k->sg_list))[0].length = 1336 TW_CL_SWAP32(req->length); 1337 } 1338 1339 cmd9k->cdb[0] = (TW_UINT8)cmd; 1340 cmd9k->cdb[4] = 128; 1341 1342 if ((error = tw_cli_submit_cmd(req))) 1343 if (error != TW_OSL_EBUSY) { 1344 tw_cli_dbg_printf(1, ctlr->ctlr_handle, 1345 tw_osl_cur_func(), 1346 "Failed to start SCSI command", 1347 "request = %p, error = %d", req, error); 1348 return(TW_OSL_EIO); 1349 } 1350 return(TW_OSL_ESUCCESS); 1351} 1352 1353 1354 1355/* 1356 * Function name: tw_cli_get_aen 1357 * Description: Sends down a Request Sense cmd to fw to fetch an AEN. 1358 * 1359 * Input: ctlr -- ptr to per ctlr structure 1360 * Output: None 1361 * Return value: 0 -- success 1362 * non-zero-- failure 1363 */ 1364TW_INT32 1365tw_cli_get_aen(struct tw_cli_ctlr_context *ctlr) 1366{ 1367 struct tw_cli_req_context *req; 1368 TW_INT32 error; 1369 1370 tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(), "entered"); 1371 1372 if ((req = tw_cli_get_request(ctlr 1373 )) == TW_CL_NULL) 1374 return(TW_OSL_EBUSY); 1375 1376 req->flags |= TW_CLI_REQ_FLAGS_INTERNAL; 1377 req->flags |= TW_CLI_REQ_FLAGS_9K; 1378 req->tw_cli_callback = tw_cli_aen_callback; 1379 if ((error = tw_cli_send_scsi_cmd(req, 0x03 /* REQUEST_SENSE */))) { 1380 tw_cli_dbg_printf(1, ctlr->ctlr_handle, tw_osl_cur_func(), 1381 "Could not send SCSI command", 1382 "request = %p, error = %d", req, error); 1383 if (req->data) 1384 ctlr->internal_req_busy = TW_CL_FALSE; 1385 tw_cli_req_q_insert_tail(req, TW_CLI_FREE_Q); 1386 } 1387 return(error); 1388} 1389 1390 1391 1392/* 1393 * Function name: tw_cli_fill_sg_list 1394 * Description: Fills in the scatter/gather list. 1395 * 1396 * Input: ctlr -- ptr to per ctlr structure 1397 * sgl_src -- ptr to fill the sg list from 1398 * sgl_dest-- ptr to sg list 1399 * nsegments--# of segments 1400 * Output: None 1401 * Return value: None 1402 */ 1403TW_VOID 1404tw_cli_fill_sg_list(struct tw_cli_ctlr_context *ctlr, TW_VOID *sgl_src, 1405 TW_VOID *sgl_dest, TW_INT32 num_sgl_entries) 1406{ 1407 TW_INT32 i; 1408 1409 tw_cli_dbg_printf(10, ctlr->ctlr_handle, tw_osl_cur_func(), "entered"); 1410 1411 if (ctlr->flags & TW_CL_64BIT_ADDRESSES) { 1412 struct tw_cl_sg_desc64 *sgl_s = 1413 (struct tw_cl_sg_desc64 *)sgl_src; 1414 struct tw_cl_sg_desc64 *sgl_d = 1415 (struct tw_cl_sg_desc64 *)sgl_dest; 1416 1417 tw_cli_dbg_printf(10, ctlr->ctlr_handle, tw_osl_cur_func(), 1418 "64 bit addresses"); 1419 for (i = 0; i < num_sgl_entries; i++) { 1420 sgl_d[i].address = TW_CL_SWAP64(sgl_s->address); 1421 sgl_d[i].length = TW_CL_SWAP32(sgl_s->length); 1422 sgl_s++; 1423 if (ctlr->flags & TW_CL_64BIT_SG_LENGTH) 1424 sgl_s = (struct tw_cl_sg_desc64 *) 1425 (((TW_INT8 *)(sgl_s)) + 4); 1426 } 1427 } else { 1428 struct tw_cl_sg_desc32 *sgl_s = 1429 (struct tw_cl_sg_desc32 *)sgl_src; 1430 struct tw_cl_sg_desc32 *sgl_d = 1431 (struct tw_cl_sg_desc32 *)sgl_dest; 1432 1433 tw_cli_dbg_printf(10, ctlr->ctlr_handle, tw_osl_cur_func(), 1434 "32 bit addresses"); 1435 for (i = 0; i < num_sgl_entries; i++) { 1436 sgl_d[i].address = TW_CL_SWAP32(sgl_s[i].address); 1437 sgl_d[i].length = TW_CL_SWAP32(sgl_s[i].length); 1438 } 1439 } 1440} 1441 1442