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