]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - sys/dev/tws/tws_hdm.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / sys / dev / tws / tws_hdm.c
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$
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
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;
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
114 void
115 tws_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
143 int
144 tws_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     req->thandle.callout = NULL;
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
218 void 
219 tws_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
242 int
243 tws_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
276 int
277 tws_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  */
361 boolean
362 tws_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
393 u_int16_t
394 tws_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
414 boolean
415 tws_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
426 void
427 tws_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
436 void
437 tws_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
446 void
447 tws_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
457 void
458 tws_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
468 boolean
469 tws_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
493 void
494 tws_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
504 void
505 tws_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
517 void
518 tws_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
535 TUNABLE_INT("hw.tws.use_32bit_sgls", &tws_use_32bit_sgls);