xref: /freebsd/sys/dev/tws/tws_hdm.c (revision d0b2dbfa)
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 
41 int tws_use_32bit_sgls=0;
42 extern u_int64_t mfa_base;
43 extern struct tws_request *tws_get_request(struct tws_softc *sc,
44                                            u_int16_t type);
45 extern void tws_q_insert_tail(struct tws_softc *sc, struct tws_request *req,
46                                 u_int8_t q_type );
47 extern struct tws_request * tws_q_remove_request(struct tws_softc *sc,
48                                    struct tws_request *req, u_int8_t q_type );
49 
50 extern void tws_cmd_complete(struct tws_request *req);
51 extern void tws_print_stats(void *arg);
52 extern int tws_send_scsi_cmd(struct tws_softc *sc, int cmd);
53 extern 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);
55 extern 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);
57 extern void tws_reset(void *arg);
58 
59 int tws_init_connect(struct tws_softc *sc, u_int16_t mc);
60 int tws_init_ctlr(struct tws_softc *sc);
61 int tws_submit_command(struct tws_softc *sc, struct tws_request *req);
62 void tws_nop_cmd(void *arg);
63 u_int16_t tws_poll4_response(struct tws_softc *sc, u_int64_t *mfa);
64 boolean tws_get_response(struct tws_softc *sc, u_int16_t *req_id,
65                                                u_int64_t *mfa);
66 boolean tws_ctlr_ready(struct tws_softc *sc);
67 void tws_turn_on_interrupts(struct tws_softc *sc);
68 void tws_turn_off_interrupts(struct tws_softc *sc);
69 boolean tws_ctlr_reset(struct tws_softc *sc);
70 void tws_assert_soft_reset(struct tws_softc *sc);
71 
72 int tws_send_generic_cmd(struct tws_softc *sc, u_int8_t opcode);
73 void tws_fetch_aen(void *arg);
74 void tws_disable_db_intr(struct tws_softc *sc);
75 void tws_enable_db_intr(struct tws_softc *sc);
76 void tws_aen_synctime_with_host(struct tws_softc *sc);
77 void tws_init_obfl_q(struct tws_softc *sc);
78 void tws_display_ctlr_info(struct tws_softc *sc);
79 
80 int
81 tws_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 
111 void
112 tws_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 
140 int
141 tws_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 
215 void
216 tws_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 
239 int
240 tws_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 
272 int
273 tws_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  */
354 boolean
355 tws_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 
382 u_int16_t
383 tws_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 
402 boolean
403 tws_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 
414 void
415 tws_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 
424 void
425 tws_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 
434 void
435 tws_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 
445 void
446 tws_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 
456 boolean
457 tws_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 
481 void
482 tws_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 
492 void
493 tws_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 
505 void
506 tws_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 
523 TUNABLE_INT("hw.tws.use_32bit_sgls", &tws_use_32bit_sgls);
524