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