xref: /freebsd/sys/dev/tws/tws_hdm.c (revision 0957b409)
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 
40 #include <dev/tws/tws.h>
41 #include <dev/tws/tws_services.h>
42 #include <dev/tws/tws_hdm.h>
43 
44 
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,
48                                            u_int16_t type);
49 extern void tws_q_insert_tail(struct tws_softc *sc, struct tws_request *req,
50                                 u_int8_t q_type );
51 extern struct tws_request * tws_q_remove_request(struct tws_softc *sc,
52                                    struct tws_request *req, u_int8_t q_type );
53 
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);
62 
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,
69                                                u_int64_t *mfa);
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);
75 
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);
83 
84 int
85 tws_init_ctlr(struct tws_softc *sc)
86 {
87     u_int64_t reg;
88     u_int32_t regh, regl;
89 
90     TWS_TRACE_DEBUG(sc, "entry", sc, sc->is64bit);
91     sc->obfl_q_overrun = false;
92     if ( tws_init_connect(sc, tws_queue_depth) )
93     {
94         TWS_TRACE_DEBUG(sc, "initConnect failed", 0, sc->is64bit);
95         return(FAILURE);
96 
97     }
98 
99 
100     while( 1 ) {
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 )
106             break;
107     }
108 
109     tws_init_obfl_q(sc);
110     tws_display_ctlr_info(sc);
111     tws_write_reg(sc, TWS_I2O0_HOBDBC, ~0, 4);
112     tws_turn_on_interrupts(sc);
113     return(SUCCESS);
114 }
115 
116 void
117 tws_init_obfl_q(struct tws_softc *sc)
118 {
119     int i=0;
120     u_int64_t paddr;
121     u_int32_t paddrh, paddrl, status;
122 
123     TWS_TRACE_DEBUG(sc, "entry", 0, sc->obfl_q_overrun);
124 
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);
131 
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;
136             break;
137         }
138         i++;
139     }
140 
141     if ( i == tws_queue_depth )
142         sc->obfl_q_overrun = false;
143 }
144 
145 int
146 tws_init_connect(struct tws_softc *sc, u_int16_t mcreadits )
147 {
148     struct tws_request *req;
149     struct tws_cmd_init_connect *initc;
150     u_int16_t reqid;
151     u_int64_t mfa;
152 
153     TWS_TRACE_DEBUG(sc, "entry", 0, mcreadits);
154 #if       0
155     req = tws_get_request(sc, TWS_REQ_TYPE_INTERNAL_CMD);
156 #else  // 0
157     req = &sc->reqs[TWS_REQ_TYPE_INTERNAL_CMD];
158     bzero(&req->cmd_pkt->cmd, sizeof(struct tws_command_apache));
159     req->data = NULL;
160     req->length = 0;
161     req->type = TWS_REQ_TYPE_INTERNAL_CMD;
162     req->flags = TWS_DIR_UNKNOWN;
163     req->error_code = TWS_REQ_RET_INVALID;
164     req->cb = NULL;
165     req->ccb_ptr = NULL;
166     callout_stop(&req->timeout);
167     req->next = req->prev = NULL;
168     req->state = TWS_REQ_STATE_BUSY;
169 #endif // 0
170 
171     if ( req == NULL ) {
172         TWS_TRACE_DEBUG(sc, "no requests", 0, 0);
173 //      device_printf(sc->tws_dev,  "No requests for initConnect\n");
174         return(FAILURE);
175     }
176 
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; */
182 
183     initc->res1__opcode =
184               BUILD_RES__OPCODE(0, TWS_FW_CMD_INIT_CONNECTION);
185     initc->size = 6;
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 */
192 
193     initc->size = 6;
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;
198 
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;
207     }
208     else {
209         /*
210          * REVISIT::If init connect fails we need to reset the ctlr
211          * and try again?
212          */
213         TWS_TRACE(sc, "unexpected req_id ", reqid, 0);
214         TWS_TRACE(sc, "INITCONNECT FAILED", reqid, 0);
215         return(FAILURE);
216     }
217     return(SUCCESS);
218 }
219 
220 void
221 tws_display_ctlr_info(struct tws_softc *sc)
222 {
223 
224     uint8_t fw_ver[16], bios_ver[16], ctlr_model[16], num_phys=0;
225     uint32_t error[4];
226 
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);
235 
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);
240     }
241 
242 }
243 
244 int
245 tws_send_generic_cmd(struct tws_softc *sc, u_int8_t opcode)
246 {
247     struct tws_request *req;
248     struct tws_cmd_generic *cmd;
249 
250     TWS_TRACE_DEBUG(sc, "entry", sc, opcode);
251     req = tws_get_request(sc, TWS_REQ_TYPE_INTERNAL_CMD);
252 
253     if ( req == NULL ) {
254         TWS_TRACE_DEBUG(sc, "no requests", 0, 0);
255         return(FAILURE);
256     }
257 
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;
262 
263     cmd->sgl_off__opcode = BUILD_RES__OPCODE(0, opcode);
264     cmd->size = 2;
265     cmd->request_id = req->request_id;
266     cmd->host_id__unit = 0;
267     cmd->status = 0;
268     cmd->flags = 0;
269     cmd->count = 0;
270 
271     req->error_code = tws_submit_command(sc, req);
272 
273     return(SUCCESS);
274 
275 }
276 
277 
278 int
279 tws_submit_command(struct tws_softc *sc, struct tws_request *req)
280 {
281     u_int32_t regl, regh;
282     u_int64_t mfa=0;
283 
284     /*
285      * mfa register  read and write must be in order.
286      * Get the io_lock to protect against simultinous
287      * passthru calls
288      */
289     mtx_lock(&sc->io_lock);
290 
291     if ( sc->obfl_q_overrun ) {
292         tws_init_obfl_q(sc);
293     }
294 
295 #ifdef TWS_PULL_MODE_ENABLE
296     regh = (u_int32_t)(req->cmd_pkt_phy >> 32);
297     /* regh = regh | TWS_MSG_ACC_MASK; */
298     mfa = regh;
299     mfa = mfa << 32;
300     regl = (u_int32_t)req->cmd_pkt_phy;
301     regl = regl | TWS_BIT0;
302     mfa = mfa | regl;
303 #else
304     regh = tws_read_reg(sc, TWS_I2O0_HIBQPH, 4);
305     mfa = regh;
306     mfa = mfa << 32;
307     regl = tws_read_reg(sc, TWS_I2O0_HIBQPL, 4);
308     mfa = mfa | regl;
309 #endif
310 
311     mtx_unlock(&sc->io_lock);
312 
313     if ( mfa == TWS_FIFO_EMPTY ) {
314         TWS_TRACE_DEBUG(sc, "inbound fifo empty", mfa, 0);
315 
316         /*
317          * Generally we should not get here.
318          * If the fifo was empty we can't do any thing much
319          * retry later
320          */
321         return(TWS_REQ_RET_PEND_NOMFA);
322 
323     }
324 
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++) {
328 
329         bus_space_write_1(sc->bus_mfa_tag, sc->bus_mfa_handle,i,
330                                ((u_int8_t *)&req->cmd_pkt->cmd)[i-mfa]);
331 
332     }
333 #endif
334 
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);
339     }
340 
341     /*
342      * mfa register  read and write must be in order.
343      * Get the io_lock to protect against simultinous
344      * passthru calls
345      */
346     mtx_lock(&sc->io_lock);
347 
348     tws_write_reg(sc, TWS_I2O0_HIBQPH, regh, 4);
349     tws_write_reg(sc, TWS_I2O0_HIBQPL, regl, 4);
350 
351     sc->stats.reqs_in++;
352     mtx_unlock(&sc->io_lock);
353 
354     return(TWS_REQ_RET_SUBMIT_SUCCESS);
355 
356 }
357 
358 /*
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
362  */
363 boolean
364 tws_get_response(struct tws_softc *sc, u_int16_t *req_id, u_int64_t *mfa)
365 {
366     u_int64_t out_mfa=0, val=0;
367     struct tws_outbound_response out_res;
368 
369     *req_id = TWS_INVALID_REQID;
370     out_mfa = (u_int64_t)tws_read_reg(sc, TWS_I2O0_HOBQPH, 4);
371 
372     if ( out_mfa == TWS_FIFO_EMPTY32 ) {
373         return(false);
374 
375     }
376     out_mfa = out_mfa << 32;
377     val = tws_read_reg(sc, TWS_I2O0_HOBQPL, 4);
378     out_mfa = out_mfa | val;
379 
380     out_res =  *(struct tws_outbound_response *)&out_mfa;
381 
382     if ( !out_res.not_mfa ) {
383         *mfa = out_mfa;
384         return(true);
385     } else {
386         *req_id = out_res.request_id;
387     }
388 
389     return(true);
390 }
391 
392 
393 
394 
395 u_int16_t
396 tws_poll4_response(struct tws_softc *sc, u_int64_t *mfa)
397 {
398     u_int16_t req_id;
399     time_t endt;
400 
401     endt = TWS_LOCAL_TIME + TWS_POLL_TIMEOUT;
402     do {
403         if(tws_get_response(sc, &req_id, mfa)) {
404 
405             if ( req_id == TWS_INVALID_REQID ) {
406                 TWS_TRACE_DEBUG(sc, "invalid req_id", 0, req_id);
407                 return(TWS_INVALID_REQID);
408             }
409             return(req_id);
410         }
411     } while (TWS_LOCAL_TIME <= endt);
412     TWS_TRACE_DEBUG(sc, "poll timeout", 0, 0);
413     return(TWS_INVALID_REQID);
414 }
415 
416 boolean
417 tws_ctlr_ready(struct tws_softc *sc)
418 {
419     u_int32_t reg;
420 
421     reg = tws_read_reg(sc, TWS_I2O0_SCRPD3, 4);
422     if ( reg & TWS_BIT13 )
423         return(true);
424     else
425         return(false);
426 }
427 
428 void
429 tws_turn_on_interrupts(struct tws_softc *sc)
430 {
431 
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);
435 
436 }
437 
438 void
439 tws_turn_off_interrupts(struct tws_softc *sc)
440 {
441 
442     TWS_TRACE_DEBUG(sc, "entry", 0, 0);
443 
444     tws_write_reg(sc, TWS_I2O0_HIMASK, ~0, 4);
445 
446 }
447 
448 void
449 tws_disable_db_intr(struct tws_softc *sc)
450 {
451     u_int32_t reg;
452 
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);
457 }
458 
459 void
460 tws_enable_db_intr(struct tws_softc *sc)
461 {
462     u_int32_t reg;
463 
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);
468 }
469 
470 boolean
471 tws_ctlr_reset(struct tws_softc *sc)
472 {
473 
474     u_int32_t reg;
475     time_t endt;
476     /* int i=0; */
477 
478     TWS_TRACE_DEBUG(sc, "entry", 0, 0);
479 
480     tws_assert_soft_reset(sc);
481 
482     do {
483         reg = tws_read_reg(sc, TWS_I2O0_SCRPD3, 4);
484     } while ( reg & TWS_BIT13 );
485 
486     endt = TWS_LOCAL_TIME + TWS_RESET_TIMEOUT;
487     do {
488         if(tws_ctlr_ready(sc))
489             return(true);
490     } while (TWS_LOCAL_TIME <= endt);
491     return(false);
492 
493 }
494 
495 void
496 tws_assert_soft_reset(struct tws_softc *sc)
497 {
498     u_int32_t reg;
499 
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);
503 
504 }
505 
506 void
507 tws_fetch_aen(void *arg)
508 {
509     struct tws_softc *sc = (struct tws_softc *)arg;
510     int error = 0;
511 
512     TWS_TRACE_DEBUG(sc, "entry", 0, 0);
513 
514     if ((error = tws_send_scsi_cmd(sc, 0x03 /* REQUEST_SENSE */))) {
515         TWS_TRACE_DEBUG(sc, "aen fetch send in progress", 0, 0);
516     }
517 }
518 
519 void
520 tws_aen_synctime_with_host(struct tws_softc *sc)
521 {
522 
523     int error;
524     long int sync_time;
525 
526     TWS_TRACE_DEBUG(sc, "entry", sc, 0);
527 
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,
532                            4, &sync_time);
533     if ( error )
534         TWS_TRACE_DEBUG(sc, "set param failed", sync_time, error);
535 }
536 
537 TUNABLE_INT("hw.tws.use_32bit_sgls", &tws_use_32bit_sgls);
538