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