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