1 /*- 2 * SPDX-License-Identifier: BSD-3-Clause 3 * 4 * Copyright (c) 2010, LSI Corp. 5 * All rights reserved. 6 * Author : Manjunath Ranganathaiah 7 * Support: freebsdraid@lsi.com 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in 17 * the documentation and/or other materials provided with the 18 * distribution. 19 * 3. Neither the name of the <ORGANIZATION> nor the names of its 20 * contributors may be used to endorse or promote products derived 21 * from this software without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 24 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 25 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 26 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 27 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 28 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 29 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 30 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 31 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 33 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 34 * POSSIBILITY OF SUCH DAMAGE. 35 * 36 * $FreeBSD$ 37 */ 38 39 40 #include <dev/tws/tws.h> 41 #include <dev/tws/tws_services.h> 42 #include <dev/tws/tws_hdm.h> 43 44 45 int tws_use_32bit_sgls=0; 46 extern u_int64_t mfa_base; 47 extern struct tws_request *tws_get_request(struct tws_softc *sc, 48 u_int16_t type); 49 extern void tws_q_insert_tail(struct tws_softc *sc, struct tws_request *req, 50 u_int8_t q_type ); 51 extern struct tws_request * tws_q_remove_request(struct tws_softc *sc, 52 struct tws_request *req, u_int8_t q_type ); 53 54 extern void tws_cmd_complete(struct tws_request *req); 55 extern void tws_print_stats(void *arg); 56 extern int tws_send_scsi_cmd(struct tws_softc *sc, int cmd); 57 extern int tws_set_param(struct tws_softc *sc, u_int32_t table_id, 58 u_int32_t param_id, u_int32_t param_size, void *data); 59 extern int tws_get_param(struct tws_softc *sc, u_int32_t table_id, 60 u_int32_t param_id, u_int32_t param_size, void *data); 61 extern void tws_reset(void *arg); 62 63 int tws_init_connect(struct tws_softc *sc, u_int16_t mc); 64 int tws_init_ctlr(struct tws_softc *sc); 65 int tws_submit_command(struct tws_softc *sc, struct tws_request *req); 66 void tws_nop_cmd(void *arg); 67 u_int16_t tws_poll4_response(struct tws_softc *sc, u_int64_t *mfa); 68 boolean tws_get_response(struct tws_softc *sc, u_int16_t *req_id, 69 u_int64_t *mfa); 70 boolean tws_ctlr_ready(struct tws_softc *sc); 71 void tws_turn_on_interrupts(struct tws_softc *sc); 72 void tws_turn_off_interrupts(struct tws_softc *sc); 73 boolean tws_ctlr_reset(struct tws_softc *sc); 74 void tws_assert_soft_reset(struct tws_softc *sc); 75 76 int tws_send_generic_cmd(struct tws_softc *sc, u_int8_t opcode); 77 void tws_fetch_aen(void *arg); 78 void tws_disable_db_intr(struct tws_softc *sc); 79 void tws_enable_db_intr(struct tws_softc *sc); 80 void tws_aen_synctime_with_host(struct tws_softc *sc); 81 void tws_init_obfl_q(struct tws_softc *sc); 82 void tws_display_ctlr_info(struct tws_softc *sc); 83 84 int 85 tws_init_ctlr(struct tws_softc *sc) 86 { 87 u_int64_t reg; 88 u_int32_t regh, regl; 89 90 TWS_TRACE_DEBUG(sc, "entry", sc, sc->is64bit); 91 sc->obfl_q_overrun = false; 92 if ( tws_init_connect(sc, tws_queue_depth) ) 93 { 94 TWS_TRACE_DEBUG(sc, "initConnect failed", 0, sc->is64bit); 95 return(FAILURE); 96 97 } 98 99 100 while( 1 ) { 101 regh = tws_read_reg(sc, TWS_I2O0_IOPOBQPH, 4); 102 regl = tws_read_reg(sc, TWS_I2O0_IOPOBQPL, 4); 103 reg = (((u_int64_t)regh) << 32) | regl; 104 TWS_TRACE_DEBUG(sc, "host outbound cleanup",reg, regl); 105 if ( regh == TWS_FIFO_EMPTY32 ) 106 break; 107 } 108 109 tws_init_obfl_q(sc); 110 tws_display_ctlr_info(sc); 111 tws_write_reg(sc, TWS_I2O0_HOBDBC, ~0, 4); 112 tws_turn_on_interrupts(sc); 113 return(SUCCESS); 114 } 115 116 void 117 tws_init_obfl_q(struct tws_softc *sc) 118 { 119 int i=0; 120 u_int64_t paddr; 121 u_int32_t paddrh, paddrl, status; 122 123 TWS_TRACE_DEBUG(sc, "entry", 0, sc->obfl_q_overrun); 124 125 while ( i < tws_queue_depth ) { 126 paddr = sc->sense_bufs[i].hdr_pkt_phy; 127 paddrh = (u_int32_t)( paddr>>32); 128 paddrl = (u_int32_t) paddr; 129 tws_write_reg(sc, TWS_I2O0_HOBQPH, paddrh, 4); 130 tws_write_reg(sc, TWS_I2O0_HOBQPL, paddrl, 4); 131 132 status = tws_read_reg(sc, TWS_I2O0_STATUS, 4); 133 if ( status & TWS_BIT13 ) { 134 device_printf(sc->tws_dev, "OBFL Overrun\n"); 135 sc->obfl_q_overrun = true; 136 break; 137 } 138 i++; 139 } 140 141 if ( i == tws_queue_depth ) 142 sc->obfl_q_overrun = false; 143 } 144 145 int 146 tws_init_connect(struct tws_softc *sc, u_int16_t mcreadits ) 147 { 148 struct tws_request *req; 149 struct tws_cmd_init_connect *initc; 150 u_int16_t reqid; 151 u_int64_t mfa; 152 153 TWS_TRACE_DEBUG(sc, "entry", 0, mcreadits); 154 #if 0 155 req = tws_get_request(sc, TWS_REQ_TYPE_INTERNAL_CMD); 156 #else // 0 157 req = &sc->reqs[TWS_REQ_TYPE_INTERNAL_CMD]; 158 bzero(&req->cmd_pkt->cmd, sizeof(struct tws_command_apache)); 159 req->data = NULL; 160 req->length = 0; 161 req->type = TWS_REQ_TYPE_INTERNAL_CMD; 162 req->flags = TWS_DIR_UNKNOWN; 163 req->error_code = TWS_REQ_RET_INVALID; 164 req->cb = NULL; 165 req->ccb_ptr = NULL; 166 callout_stop(&req->timeout); 167 req->next = req->prev = NULL; 168 req->state = TWS_REQ_STATE_BUSY; 169 #endif // 0 170 171 if ( req == NULL ) { 172 TWS_TRACE_DEBUG(sc, "no requests", 0, 0); 173 // device_printf(sc->tws_dev, "No requests for initConnect\n"); 174 return(FAILURE); 175 } 176 177 tws_swap16(0xbeef); /* just for test */ 178 tws_swap32(0xdeadbeef); /* just for test */ 179 tws_swap64(0xdeadbeef); /* just for test */ 180 initc = &(req->cmd_pkt->cmd.pkt_g.init_connect); 181 /* req->cmd_pkt->hdr.header_desc.size_header = 128; */ 182 183 initc->res1__opcode = 184 BUILD_RES__OPCODE(0, TWS_FW_CMD_INIT_CONNECTION); 185 initc->size = 6; 186 initc->request_id = req->request_id; 187 initc->message_credits = mcreadits; 188 initc->features |= TWS_BIT_EXTEND; 189 if ( sc->is64bit && !tws_use_32bit_sgls ) 190 initc->features |= TWS_64BIT_SG_ADDRESSES; 191 /* assuming set features is always on */ 192 193 initc->size = 6; 194 initc->fw_srl = sc->cinfo.working_srl = TWS_CURRENT_FW_SRL; 195 initc->fw_arch_id = 0; 196 initc->fw_branch = sc->cinfo.working_branch = 0; 197 initc->fw_build = sc->cinfo.working_build = 0; 198 199 req->error_code = tws_submit_command(sc, req); 200 reqid = tws_poll4_response(sc, &mfa); 201 if ( reqid != TWS_INVALID_REQID && reqid == req->request_id ) { 202 sc->cinfo.fw_on_ctlr_srl = initc->fw_srl; 203 sc->cinfo.fw_on_ctlr_branch = initc->fw_branch; 204 sc->cinfo.fw_on_ctlr_build = initc->fw_build; 205 sc->stats.reqs_out++; 206 req->state = TWS_REQ_STATE_FREE; 207 } 208 else { 209 /* 210 * REVISIT::If init connect fails we need to reset the ctlr 211 * and try again? 212 */ 213 TWS_TRACE(sc, "unexpected req_id ", reqid, 0); 214 TWS_TRACE(sc, "INITCONNECT FAILED", reqid, 0); 215 return(FAILURE); 216 } 217 return(SUCCESS); 218 } 219 220 void 221 tws_display_ctlr_info(struct tws_softc *sc) 222 { 223 224 uint8_t fw_ver[16], bios_ver[16], ctlr_model[16], num_phys=0; 225 uint32_t error[4]; 226 227 error[0] = tws_get_param(sc, TWS_PARAM_PHYS_TABLE, 228 TWS_PARAM_CONTROLLER_PHYS_COUNT, 1, &num_phys); 229 error[1] = tws_get_param(sc, TWS_PARAM_VERSION_TABLE, 230 TWS_PARAM_VERSION_FW, 16, fw_ver); 231 error[2] = tws_get_param(sc, TWS_PARAM_VERSION_TABLE, 232 TWS_PARAM_VERSION_BIOS, 16, bios_ver); 233 error[3] = tws_get_param(sc, TWS_PARAM_VERSION_TABLE, 234 TWS_PARAM_CTLR_MODEL, 16, ctlr_model); 235 236 if ( !error[0] && !error[1] && !error[2] && !error[3] ) { 237 device_printf( sc->tws_dev, 238 "Controller details: Model %.16s, %d Phys, Firmware %.16s, BIOS %.16s\n", 239 ctlr_model, num_phys, fw_ver, bios_ver); 240 } 241 242 } 243 244 int 245 tws_send_generic_cmd(struct tws_softc *sc, u_int8_t opcode) 246 { 247 struct tws_request *req; 248 struct tws_cmd_generic *cmd; 249 250 TWS_TRACE_DEBUG(sc, "entry", sc, opcode); 251 req = tws_get_request(sc, TWS_REQ_TYPE_INTERNAL_CMD); 252 253 if ( req == NULL ) { 254 TWS_TRACE_DEBUG(sc, "no requests", 0, 0); 255 return(FAILURE); 256 } 257 258 cmd = &(req->cmd_pkt->cmd.pkt_g.generic); 259 bzero(cmd, sizeof(struct tws_cmd_generic)); 260 /* req->cmd_pkt->hdr.header_desc.size_header = 128; */ 261 req->cb = tws_cmd_complete; 262 263 cmd->sgl_off__opcode = BUILD_RES__OPCODE(0, opcode); 264 cmd->size = 2; 265 cmd->request_id = req->request_id; 266 cmd->host_id__unit = 0; 267 cmd->status = 0; 268 cmd->flags = 0; 269 cmd->count = 0; 270 271 req->error_code = tws_submit_command(sc, req); 272 273 return(SUCCESS); 274 275 } 276 277 278 int 279 tws_submit_command(struct tws_softc *sc, struct tws_request *req) 280 { 281 u_int32_t regl, regh; 282 u_int64_t mfa=0; 283 284 /* 285 * mfa register read and write must be in order. 286 * Get the io_lock to protect against simultinous 287 * passthru calls 288 */ 289 mtx_lock(&sc->io_lock); 290 291 if ( sc->obfl_q_overrun ) { 292 tws_init_obfl_q(sc); 293 } 294 295 #ifdef TWS_PULL_MODE_ENABLE 296 regh = (u_int32_t)(req->cmd_pkt_phy >> 32); 297 /* regh = regh | TWS_MSG_ACC_MASK; */ 298 mfa = regh; 299 mfa = mfa << 32; 300 regl = (u_int32_t)req->cmd_pkt_phy; 301 regl = regl | TWS_BIT0; 302 mfa = mfa | regl; 303 #else 304 regh = tws_read_reg(sc, TWS_I2O0_HIBQPH, 4); 305 mfa = regh; 306 mfa = mfa << 32; 307 regl = tws_read_reg(sc, TWS_I2O0_HIBQPL, 4); 308 mfa = mfa | regl; 309 #endif 310 311 mtx_unlock(&sc->io_lock); 312 313 if ( mfa == TWS_FIFO_EMPTY ) { 314 TWS_TRACE_DEBUG(sc, "inbound fifo empty", mfa, 0); 315 316 /* 317 * Generally we should not get here. 318 * If the fifo was empty we can't do any thing much 319 * retry later 320 */ 321 return(TWS_REQ_RET_PEND_NOMFA); 322 323 } 324 325 #ifndef TWS_PULL_MODE_ENABLE 326 for (int i=mfa; i<(sizeof(struct tws_command_packet)+ mfa - 327 sizeof( struct tws_command_header)); i++) { 328 329 bus_space_write_1(sc->bus_mfa_tag, sc->bus_mfa_handle,i, 330 ((u_int8_t *)&req->cmd_pkt->cmd)[i-mfa]); 331 332 } 333 #endif 334 335 if ( req->type == TWS_REQ_TYPE_SCSI_IO ) { 336 mtx_lock(&sc->q_lock); 337 tws_q_insert_tail(sc, req, TWS_BUSY_Q); 338 mtx_unlock(&sc->q_lock); 339 } 340 341 /* 342 * mfa register read and write must be in order. 343 * Get the io_lock to protect against simultinous 344 * passthru calls 345 */ 346 mtx_lock(&sc->io_lock); 347 348 tws_write_reg(sc, TWS_I2O0_HIBQPH, regh, 4); 349 tws_write_reg(sc, TWS_I2O0_HIBQPL, regl, 4); 350 351 sc->stats.reqs_in++; 352 mtx_unlock(&sc->io_lock); 353 354 return(TWS_REQ_RET_SUBMIT_SUCCESS); 355 356 } 357 358 /* 359 * returns true if the respose was available othewise, false. 360 * In the case of error the arg mfa will contain the address and 361 * req_id will be TWS_INVALID_REQID 362 */ 363 boolean 364 tws_get_response(struct tws_softc *sc, u_int16_t *req_id, u_int64_t *mfa) 365 { 366 u_int64_t out_mfa=0, val=0; 367 struct tws_outbound_response out_res; 368 369 *req_id = TWS_INVALID_REQID; 370 out_mfa = (u_int64_t)tws_read_reg(sc, TWS_I2O0_HOBQPH, 4); 371 372 if ( out_mfa == TWS_FIFO_EMPTY32 ) { 373 return(false); 374 375 } 376 out_mfa = out_mfa << 32; 377 val = tws_read_reg(sc, TWS_I2O0_HOBQPL, 4); 378 out_mfa = out_mfa | val; 379 380 out_res = *(struct tws_outbound_response *)&out_mfa; 381 382 if ( !out_res.not_mfa ) { 383 *mfa = out_mfa; 384 return(true); 385 } else { 386 *req_id = out_res.request_id; 387 } 388 389 return(true); 390 } 391 392 393 394 395 u_int16_t 396 tws_poll4_response(struct tws_softc *sc, u_int64_t *mfa) 397 { 398 u_int16_t req_id; 399 time_t endt; 400 401 endt = TWS_LOCAL_TIME + TWS_POLL_TIMEOUT; 402 do { 403 if(tws_get_response(sc, &req_id, mfa)) { 404 405 if ( req_id == TWS_INVALID_REQID ) { 406 TWS_TRACE_DEBUG(sc, "invalid req_id", 0, req_id); 407 return(TWS_INVALID_REQID); 408 } 409 return(req_id); 410 } 411 } while (TWS_LOCAL_TIME <= endt); 412 TWS_TRACE_DEBUG(sc, "poll timeout", 0, 0); 413 return(TWS_INVALID_REQID); 414 } 415 416 boolean 417 tws_ctlr_ready(struct tws_softc *sc) 418 { 419 u_int32_t reg; 420 421 reg = tws_read_reg(sc, TWS_I2O0_SCRPD3, 4); 422 if ( reg & TWS_BIT13 ) 423 return(true); 424 else 425 return(false); 426 } 427 428 void 429 tws_turn_on_interrupts(struct tws_softc *sc) 430 { 431 432 TWS_TRACE_DEBUG(sc, "entry", 0, 0); 433 /* turn on response and db interrupt only */ 434 tws_write_reg(sc, TWS_I2O0_HIMASK, TWS_BIT0, 4); 435 436 } 437 438 void 439 tws_turn_off_interrupts(struct tws_softc *sc) 440 { 441 442 TWS_TRACE_DEBUG(sc, "entry", 0, 0); 443 444 tws_write_reg(sc, TWS_I2O0_HIMASK, ~0, 4); 445 446 } 447 448 void 449 tws_disable_db_intr(struct tws_softc *sc) 450 { 451 u_int32_t reg; 452 453 TWS_TRACE_DEBUG(sc, "entry", 0, 0); 454 reg = tws_read_reg(sc, TWS_I2O0_HIMASK, 4); 455 reg = reg | TWS_BIT2; 456 tws_write_reg(sc, TWS_I2O0_HIMASK, reg, 4); 457 } 458 459 void 460 tws_enable_db_intr(struct tws_softc *sc) 461 { 462 u_int32_t reg; 463 464 TWS_TRACE_DEBUG(sc, "entry", 0, 0); 465 reg = tws_read_reg(sc, TWS_I2O0_HIMASK, 4); 466 reg = reg & ~TWS_BIT2; 467 tws_write_reg(sc, TWS_I2O0_HIMASK, reg, 4); 468 } 469 470 boolean 471 tws_ctlr_reset(struct tws_softc *sc) 472 { 473 474 u_int32_t reg; 475 time_t endt; 476 /* int i=0; */ 477 478 TWS_TRACE_DEBUG(sc, "entry", 0, 0); 479 480 tws_assert_soft_reset(sc); 481 482 do { 483 reg = tws_read_reg(sc, TWS_I2O0_SCRPD3, 4); 484 } while ( reg & TWS_BIT13 ); 485 486 endt = TWS_LOCAL_TIME + TWS_RESET_TIMEOUT; 487 do { 488 if(tws_ctlr_ready(sc)) 489 return(true); 490 } while (TWS_LOCAL_TIME <= endt); 491 return(false); 492 493 } 494 495 void 496 tws_assert_soft_reset(struct tws_softc *sc) 497 { 498 u_int32_t reg; 499 500 reg = tws_read_reg(sc, TWS_I2O0_HIBDB, 4); 501 TWS_TRACE_DEBUG(sc, "in bound door bell read ", reg, TWS_I2O0_HIBDB); 502 tws_write_reg(sc, TWS_I2O0_HIBDB, reg | TWS_BIT8, 4); 503 504 } 505 506 void 507 tws_fetch_aen(void *arg) 508 { 509 struct tws_softc *sc = (struct tws_softc *)arg; 510 int error = 0; 511 512 TWS_TRACE_DEBUG(sc, "entry", 0, 0); 513 514 if ((error = tws_send_scsi_cmd(sc, 0x03 /* REQUEST_SENSE */))) { 515 TWS_TRACE_DEBUG(sc, "aen fetch send in progress", 0, 0); 516 } 517 } 518 519 void 520 tws_aen_synctime_with_host(struct tws_softc *sc) 521 { 522 523 int error; 524 long int sync_time; 525 526 TWS_TRACE_DEBUG(sc, "entry", sc, 0); 527 528 sync_time = (TWS_LOCAL_TIME - (3 * 86400)) % 604800; 529 TWS_TRACE_DEBUG(sc, "sync_time,ts", sync_time, time_second); 530 TWS_TRACE_DEBUG(sc, "utc_offset", utc_offset(), 0); 531 error = tws_set_param(sc, TWS_PARAM_TIME_TABLE, TWS_PARAM_TIME_SCHED_TIME, 532 4, &sync_time); 533 if ( error ) 534 TWS_TRACE_DEBUG(sc, "set param failed", sync_time, error); 535 } 536 537 TUNABLE_INT("hw.tws.use_32bit_sgls", &tws_use_32bit_sgls); 538