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