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