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