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