2 * SPDX-License-Identifier: BSD-3-Clause
4 * Copyright (c) 2010, LSI Corp.
6 * Author : Manjunath Ranganathaiah
7 * Support: freebsdraid@lsi.com
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
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
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.
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.
40 #include <dev/tws/tws.h>
41 #include <dev/tws/tws_services.h>
42 #include <dev/tws/tws_hdm.h>
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,
49 extern void tws_q_insert_tail(struct tws_softc *sc, struct tws_request *req,
51 extern struct tws_request * tws_q_remove_request(struct tws_softc *sc,
52 struct tws_request *req, u_int8_t q_type );
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);
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,
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);
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);
85 tws_init_ctlr(struct tws_softc *sc)
90 TWS_TRACE_DEBUG(sc, "entry", sc, sc->is64bit);
91 sc->obfl_q_overrun = false;
92 if ( tws_init_connect(sc, tws_queue_depth) )
94 TWS_TRACE_DEBUG(sc, "initConnect failed", 0, sc->is64bit);
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 )
110 tws_display_ctlr_info(sc);
111 tws_write_reg(sc, TWS_I2O0_HOBDBC, ~0, 4);
112 tws_turn_on_interrupts(sc);
117 tws_init_obfl_q(struct tws_softc *sc)
121 u_int32_t paddrh, paddrl, status;
123 TWS_TRACE_DEBUG(sc, "entry", 0, sc->obfl_q_overrun);
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);
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;
141 if ( i == tws_queue_depth )
142 sc->obfl_q_overrun = false;
146 tws_init_connect(struct tws_softc *sc, u_int16_t mcreadits )
148 struct tws_request *req;
149 struct tws_cmd_init_connect *initc;
153 TWS_TRACE_DEBUG(sc, "entry", 0, mcreadits);
155 req = tws_get_request(sc, TWS_REQ_TYPE_INTERNAL_CMD);
157 req = &sc->reqs[TWS_REQ_TYPE_INTERNAL_CMD];
158 bzero(&req->cmd_pkt->cmd, sizeof(struct tws_command_apache));
161 req->type = TWS_REQ_TYPE_INTERNAL_CMD;
162 req->flags = TWS_DIR_UNKNOWN;
163 req->error_code = TWS_REQ_RET_INVALID;
166 callout_stop(&req->timeout);
167 req->next = req->prev = NULL;
168 req->state = TWS_REQ_STATE_BUSY;
172 TWS_TRACE_DEBUG(sc, "no requests", 0, 0);
173 // device_printf(sc->tws_dev, "No requests for initConnect\n");
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; */
183 initc->res1__opcode =
184 BUILD_RES__OPCODE(0, TWS_FW_CMD_INIT_CONNECTION);
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 */
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;
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;
210 * REVISIT::If init connect fails we need to reset the ctlr
213 TWS_TRACE(sc, "unexpected req_id ", reqid, 0);
214 TWS_TRACE(sc, "INITCONNECT FAILED", reqid, 0);
221 tws_display_ctlr_info(struct tws_softc *sc)
224 uint8_t fw_ver[16], bios_ver[16], ctlr_model[16], num_phys=0;
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);
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);
245 tws_send_generic_cmd(struct tws_softc *sc, u_int8_t opcode)
247 struct tws_request *req;
248 struct tws_cmd_generic *cmd;
250 TWS_TRACE_DEBUG(sc, "entry", sc, opcode);
251 req = tws_get_request(sc, TWS_REQ_TYPE_INTERNAL_CMD);
254 TWS_TRACE_DEBUG(sc, "no requests", 0, 0);
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;
263 cmd->sgl_off__opcode = BUILD_RES__OPCODE(0, opcode);
265 cmd->request_id = req->request_id;
266 cmd->host_id__unit = 0;
271 req->error_code = tws_submit_command(sc, req);
279 tws_submit_command(struct tws_softc *sc, struct tws_request *req)
281 u_int32_t regl, regh;
285 * mfa register read and write must be in order.
286 * Get the io_lock to protect against simultinous
289 mtx_lock(&sc->io_lock);
291 if ( sc->obfl_q_overrun ) {
295 #ifdef TWS_PULL_MODE_ENABLE
296 regh = (u_int32_t)(req->cmd_pkt_phy >> 32);
297 /* regh = regh | TWS_MSG_ACC_MASK; */
300 regl = (u_int32_t)req->cmd_pkt_phy;
301 regl = regl | TWS_BIT0;
304 regh = tws_read_reg(sc, TWS_I2O0_HIBQPH, 4);
307 regl = tws_read_reg(sc, TWS_I2O0_HIBQPL, 4);
311 mtx_unlock(&sc->io_lock);
313 if ( mfa == TWS_FIFO_EMPTY ) {
314 TWS_TRACE_DEBUG(sc, "inbound fifo empty", mfa, 0);
317 * Generally we should not get here.
318 * If the fifo was empty we can't do any thing much
321 return(TWS_REQ_RET_PEND_NOMFA);
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++) {
329 bus_space_write_1(sc->bus_mfa_tag, sc->bus_mfa_handle,i,
330 ((u_int8_t *)&req->cmd_pkt->cmd)[i-mfa]);
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);
342 * mfa register read and write must be in order.
343 * Get the io_lock to protect against simultinous
346 mtx_lock(&sc->io_lock);
348 tws_write_reg(sc, TWS_I2O0_HIBQPH, regh, 4);
349 tws_write_reg(sc, TWS_I2O0_HIBQPL, regl, 4);
352 mtx_unlock(&sc->io_lock);
354 return(TWS_REQ_RET_SUBMIT_SUCCESS);
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
364 tws_get_response(struct tws_softc *sc, u_int16_t *req_id, u_int64_t *mfa)
366 u_int64_t out_mfa=0, val=0;
367 struct tws_outbound_response out_res;
369 *req_id = TWS_INVALID_REQID;
370 out_mfa = (u_int64_t)tws_read_reg(sc, TWS_I2O0_HOBQPH, 4);
372 if ( out_mfa == TWS_FIFO_EMPTY32 ) {
376 out_mfa = out_mfa << 32;
377 val = tws_read_reg(sc, TWS_I2O0_HOBQPL, 4);
378 out_mfa = out_mfa | val;
380 out_res = *(struct tws_outbound_response *)&out_mfa;
382 if ( !out_res.not_mfa ) {
386 *req_id = out_res.request_id;
396 tws_poll4_response(struct tws_softc *sc, u_int64_t *mfa)
401 endt = TWS_LOCAL_TIME + TWS_POLL_TIMEOUT;
403 if(tws_get_response(sc, &req_id, mfa)) {
405 if ( req_id == TWS_INVALID_REQID ) {
406 TWS_TRACE_DEBUG(sc, "invalid req_id", 0, req_id);
407 return(TWS_INVALID_REQID);
411 } while (TWS_LOCAL_TIME <= endt);
412 TWS_TRACE_DEBUG(sc, "poll timeout", 0, 0);
413 return(TWS_INVALID_REQID);
417 tws_ctlr_ready(struct tws_softc *sc)
421 reg = tws_read_reg(sc, TWS_I2O0_SCRPD3, 4);
422 if ( reg & TWS_BIT13 )
429 tws_turn_on_interrupts(struct tws_softc *sc)
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);
439 tws_turn_off_interrupts(struct tws_softc *sc)
442 TWS_TRACE_DEBUG(sc, "entry", 0, 0);
444 tws_write_reg(sc, TWS_I2O0_HIMASK, ~0, 4);
449 tws_disable_db_intr(struct tws_softc *sc)
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);
460 tws_enable_db_intr(struct tws_softc *sc)
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);
471 tws_ctlr_reset(struct tws_softc *sc)
478 TWS_TRACE_DEBUG(sc, "entry", 0, 0);
480 tws_assert_soft_reset(sc);
483 reg = tws_read_reg(sc, TWS_I2O0_SCRPD3, 4);
484 } while ( reg & TWS_BIT13 );
486 endt = TWS_LOCAL_TIME + TWS_RESET_TIMEOUT;
488 if(tws_ctlr_ready(sc))
490 } while (TWS_LOCAL_TIME <= endt);
496 tws_assert_soft_reset(struct tws_softc *sc)
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);
507 tws_fetch_aen(void *arg)
509 struct tws_softc *sc = (struct tws_softc *)arg;
512 TWS_TRACE_DEBUG(sc, "entry", 0, 0);
514 if ((error = tws_send_scsi_cmd(sc, 0x03 /* REQUEST_SENSE */))) {
515 TWS_TRACE_DEBUG(sc, "aen fetch send in progress", 0, 0);
520 tws_aen_synctime_with_host(struct tws_softc *sc)
526 TWS_TRACE_DEBUG(sc, "entry", sc, 0);
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,
534 TWS_TRACE_DEBUG(sc, "set param failed", sync_time, error);
537 TUNABLE_INT("hw.tws.use_32bit_sgls", &tws_use_32bit_sgls);