tws_hdm.c revision 272000
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: head/sys/dev/tws/tws_hdm.c 272000 2014-09-22 20:38:01Z jhb $
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