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