File: /usr/src/linux/arch/ia64/sn/io/l1_command.c
1 /* $Id$
2 *
3 * This file is subject to the terms and conditions of the GNU General Public
4 * License. See the file "COPYING" in the main directory of this archive
5 * for more details.
6 *
7 * Copyright (C) 1992 - 1997, 2000 Silicon Graphics, Inc.
8 * Copyright (C) 2000 by Colin Ngam
9 */
10
11 #include <linux/types.h>
12 #include <linux/slab.h>
13 #include <asm/sn/sgi.h>
14 #include <asm/sn/iograph.h>
15 #include <asm/sn/invent.h>
16 #include <asm/sn/hcl.h>
17 #include <asm/sn/hcl_util.h>
18 #include <asm/sn/labelcl.h>
19 #include <asm/sn/eeprom.h>
20 #include <asm/sn/ksys/i2c.h>
21 #include <asm/sn/router.h>
22 #include <asm/sn/module.h>
23 #include <asm/sn/ksys/l1.h>
24 #include <asm/sn/nodepda.h>
25 #include <asm/sn/clksupport.h>
26
27 #define ELSC_TIMEOUT 1000000 /* ELSC response timeout (usec) */
28 #define LOCK_TIMEOUT 5000000 /* Hub lock timeout (usec) */
29
30 #define LOCAL_HUB LOCAL_HUB_ADDR
31 #define LD(x) (*(volatile uint64_t *)(x))
32 #define SD(x, v) (LD(x) = (uint64_t) (v))
33
34 #define hub_cpu_get() 0
35
36 #define LBYTE(caddr) (*(char *) caddr)
37
38 extern char *bcopy(const char * src, char * dest, int count);
39
40 #define LDEBUG 0
41
42 /*
43 * ELSC data is in NVRAM page 7 at the following offsets.
44 */
45
46 #define NVRAM_MAGIC_AD 0x700 /* magic number used for init */
47 #define NVRAM_PASS_WD 0x701 /* password (4 bytes in length) */
48 #define NVRAM_DBG1 0x705 /* virtual XOR debug switches */
49 #define NVRAM_DBG2 0x706 /* physical XOR debug switches */
50 #define NVRAM_CFG 0x707 /* ELSC Configuration info */
51 #define NVRAM_MODULE 0x708 /* system module number */
52 #define NVRAM_BIST_FLG 0x709 /* BIST flags (2 bits per nodeboard) */
53 #define NVRAM_PARTITION 0x70a /* module's partition id */
54 #define NVRAM_DOMAIN 0x70b /* module's domain id */
55 #define NVRAM_CLUSTER 0x70c /* module's cluster id */
56 #define NVRAM_CELL 0x70d /* module's cellid */
57
58 #define NVRAM_MAGIC_NO 0x37 /* value of magic number */
59 #define NVRAM_SIZE 16 /* 16 bytes in nvram */
60
61 /*
62 * Declare a static ELSC NVRAM buffer to hold all data read from
63 * and written to NVRAM. This nvram "cache" will be used only during the
64 * IP27prom execution.
65 */
66 static char elsc_nvram_buffer[NVRAM_SIZE];
67
68 #define SC_COMMAND sc_command
69
70 /*
71 * elsc_init
72 *
73 * Initialize ELSC structure
74 */
75
76 void elsc_init(elsc_t *e, nasid_t nasid)
77 {
78 sc_init((l1sc_t *)e, nasid, BRL1_LOCALUART);
79 }
80
81
82 /*
83 * elsc_errmsg
84 *
85 * Given a negative error code,
86 * returns a corresponding static error string.
87 */
88
89 char *elsc_errmsg(int code)
90 {
91 switch (code) {
92 case ELSC_ERROR_CMD_SEND:
93 return "Command send error";
94 case ELSC_ERROR_CMD_CHECKSUM:
95 return "Command packet checksum error";
96 case ELSC_ERROR_CMD_UNKNOWN:
97 return "Unknown command";
98 case ELSC_ERROR_CMD_ARGS:
99 return "Invalid command argument(s)";
100 case ELSC_ERROR_CMD_PERM:
101 return "Permission denied";
102 case ELSC_ERROR_RESP_TIMEOUT:
103 return "System controller response timeout";
104 case ELSC_ERROR_RESP_CHECKSUM:
105 return "Response packet checksum error";
106 case ELSC_ERROR_RESP_FORMAT:
107 return "Response format error";
108 case ELSC_ERROR_RESP_DIR:
109 return "Response direction error";
110 case ELSC_ERROR_MSG_LOST:
111 return "Message lost because queue is full";
112 case ELSC_ERROR_LOCK_TIMEOUT:
113 return "Timed out getting ELSC lock";
114 case ELSC_ERROR_DATA_SEND:
115 return "Error sending data";
116 case ELSC_ERROR_NIC:
117 return "NIC protocol error";
118 case ELSC_ERROR_NVMAGIC:
119 return "Bad magic number in NVRAM";
120 case ELSC_ERROR_MODULE:
121 return "Module location protocol error";
122 default:
123 return "Unknown error";
124 }
125 }
126
127 /*
128 * elsc_nvram_init
129 *
130 * Initializes reads and writes to NVRAM. This will perform a single
131 * read to NVRAM, getting all data at once. When the PROM tries to
132 * read NVRAM, it returns the data from the buffer being read. If the
133 * PROM tries to write out to NVRAM, the write is done, and the internal
134 * buffer is updated.
135 */
136
137 void elsc_nvram_init(nasid_t nasid, uchar_t *elsc_nvram_data)
138 {
139 /* This might require implementation of multiple-packet request/responses
140 * if it's to provide the same behavior that was available in SN0.
141 */
142 nasid = nasid;
143 elsc_nvram_data = elsc_nvram_data;
144 }
145
146 /*
147 * elsc_nvram_copy
148 *
149 * Copies the content of a buffer into the static buffer in this library.
150 */
151
152 void elsc_nvram_copy(uchar_t *elsc_nvram_data)
153 {
154 memcpy(elsc_nvram_buffer, elsc_nvram_data, NVRAM_SIZE);
155 }
156
157 /*
158 * elsc_nvram_write
159 *
160 * Copies bytes from 'buf' into NVRAM, starting at NVRAM address
161 * 'addr' which must be between 0 and 2047.
162 *
163 * If 'len' is non-negative, the routine copies 'len' bytes.
164 *
165 * If 'len' is negative, the routine treats the data as a string and
166 * copies bytes up to and including a NUL-terminating zero, but not
167 * to exceed '-len' bytes.
168 */
169
170 int elsc_nvram_write(elsc_t *e, int addr, char *buf, int len)
171 {
172 /* Here again, we might need to work out the details of a
173 * multiple-packet protocol.
174 */
175
176 /* For now, pretend it worked. */
177 e = e;
178 addr = addr;
179 buf = buf;
180 return (len < 0 ? -len : len);
181 }
182
183 /*
184 * elsc_nvram_read
185 *
186 * Copies bytes from NVRAM into 'buf', starting at NVRAM address
187 * 'addr' which must be between 0 and 2047.
188 *
189 * If 'len' is non-negative, the routine copies 'len' bytes.
190 *
191 * If 'len' is negative, the routine treats the data as a string and
192 * copies bytes up to and including a NUL-terminating zero, but not
193 * to exceed '-len' bytes. NOTE: This method is no longer supported.
194 * It was never used in the first place.
195 */
196
197 int elsc_nvram_read(elsc_t *e, int addr, char *buf, int len)
198 {
199 /* multiple packets? */
200 e = e;
201 addr = addr;
202 buf = buf;
203 len = len;
204 return -1;
205 }
206
207
208 /*
209 * Command Set
210 */
211
212 int elsc_version(elsc_t *e, char *result)
213 {
214 char msg[BRL1_QSIZE];
215 int len; /* length of message being sent */
216 int subch; /* system controller subchannel used */
217 int major, /* major rev number */
218 minor, /* minor rev number */
219 bugfix; /* bugfix rev number */
220
221 /* fill in msg with the opcode & params */
222 bzero( msg, BRL1_QSIZE );
223 subch = sc_open( (l1sc_t *)e, L1_ADDR_LOCAL );
224
225 if( (len = sc_construct_msg( (l1sc_t *)e, subch, msg, BRL1_QSIZE,
226 L1_ADDR_TASK_GENERAL,
227 L1_REQ_FW_REV, 0 )) < 0 )
228 {
229 sc_close( e, subch );
230 return( ELSC_ERROR_CMD_ARGS );
231 }
232
233 /* send the request to the L1 */
234 if( SC_COMMAND( (l1sc_t *)e, subch, msg, msg, &len ) < 0 )
235 {
236 sc_close( e, subch );
237 return( ELSC_ERROR_CMD_SEND );
238 }
239
240 /* free up subchannel */
241 sc_close( (l1sc_t *)e, subch );
242
243 /* check response */
244 if( sc_interpret_resp( msg, 6, L1_ARG_INT, &major,
245 L1_ARG_INT, &minor, L1_ARG_INT, &bugfix )
246 < 0 )
247 {
248 return( ELSC_ERROR_RESP_FORMAT );
249 }
250
251 sprintf( result, "%d.%d.%d", major, minor, bugfix );
252
253 return 0;
254 }
255
256 int elsc_debug_set(elsc_t *e, u_char byte1, u_char byte2)
257 {
258 /* shush compiler */
259 e = e;
260 byte1 = byte1;
261 byte2 = byte2;
262
263 /* fill in a buffer with the opcode & params; call sc_command */
264
265 return 0;
266 }
267
268 int elsc_debug_get(elsc_t *e, u_char *byte1, u_char *byte2)
269 {
270 char msg[BRL1_QSIZE];
271 int subch; /* system controller subchannel used */
272 int dbg_sw; /* holds debug switch settings */
273 int len; /* number of msg buffer bytes used */
274
275 /* fill in msg with the opcode & params */
276 bzero( msg, BRL1_QSIZE );
277 if( (subch = sc_open( (l1sc_t *)e, L1_ADDR_LOCAL )) < 0 ) {
278 return( ELSC_ERROR_CMD_SEND );
279 }
280
281 if( (len = sc_construct_msg( (l1sc_t *)e, subch, msg, BRL1_QSIZE,
282 L1_ADDR_TASK_GENERAL,
283 L1_REQ_RDBG, 0 ) ) < 0 )
284 {
285 sc_close( e, subch );
286 return( ELSC_ERROR_CMD_ARGS );
287 }
288
289 /* send the request to the L1 */
290 if( sc_command( (l1sc_t *)e, subch, msg, msg, &len ) < 0 )
291 {
292 sc_close( e, subch );
293 return( ELSC_ERROR_CMD_SEND );
294 }
295
296 /* free up subchannel */
297 sc_close( (l1sc_t *)e, subch );
298
299 /* check response */
300 if( sc_interpret_resp( msg, 2, L1_ARG_INT, &dbg_sw ) < 0 )
301 {
302 return( ELSC_ERROR_RESP_FORMAT );
303 }
304
305 /* copy out debug switch settings (last two bytes of the
306 * integer response)
307 */
308 *byte1 = ((dbg_sw >> 8) & 0xFF);
309 *byte2 = (dbg_sw & 0xFF);
310
311 return 0;
312 }
313
314
315 /*
316 * elsc_rack_bay_get fills in the two int * arguments with the
317 * rack number and bay number of the L1 being addressed
318 */
319 int elsc_rack_bay_get(elsc_t *e, uint *rack, uint *bay)
320 {
321 char msg[BRL1_QSIZE]; /* L1 request/response info */
322 int subch; /* system controller subchannel used */
323 int len; /* length of message */
324 uint32_t buf32; /* used to copy 32-bit rack/bay out of msg */
325
326 /* fill in msg with the opcode & params */
327 bzero( msg, BRL1_QSIZE );
328 if( (subch = sc_open( (l1sc_t *)e, L1_ADDR_LOCAL )) < 0 ) {
329 return( ELSC_ERROR_CMD_SEND );
330 }
331
332 if( (len = sc_construct_msg( (l1sc_t *)e, subch, msg, BRL1_QSIZE,
333 L1_ADDR_TASK_GENERAL,
334 L1_REQ_RRACK, 0 )) < 0 )
335 {
336 sc_close( e, subch );
337 return( ELSC_ERROR_CMD_ARGS );
338 }
339
340
341 /* send the request to the L1 */
342 if( sc_command( (l1sc_t *)e, subch, msg, msg, &len ) ) {
343 sc_close( e, subch );
344 return( ELSC_ERROR_CMD_SEND );
345 }
346
347 /* free up subchannel */
348 sc_close(e, subch);
349
350 /* check response */
351 if( sc_interpret_resp( msg, 2, L1_ARG_INT, &buf32 ) < 0 )
352 {
353 return( ELSC_ERROR_RESP_FORMAT );
354 }
355
356 /* extract rack/bay info
357 *
358 * note that the 32-bit value returned by the L1 actually
359 * only uses the low-order sixteen bits for rack and bay
360 * information. A "normal" L1 address puts rack and bay
361 * information in bit positions 12 through 28. So if
362 * we initially shift the value returned 12 bits to the left,
363 * we can use the L1 addressing #define's to extract the
364 * values we need (see ksys/l1.h for a complete list of the
365 * various fields of an L1 address).
366 */
367 buf32 <<= L1_ADDR_BAY_SHFT;
368
369 *rack = (buf32 & L1_ADDR_RACK_MASK) >> L1_ADDR_RACK_SHFT;
370 *bay = (buf32 & L1_ADDR_BAY_MASK) >> L1_ADDR_BAY_SHFT;
371
372 return 0;
373 }
374
375
376 /* elsc_rack_bay_type_get fills in the three int * arguments with the
377 * rack number, bay number and brick type of the L1 being addressed. Note
378 * that if the L1 operation fails and this function returns an error value,
379 * garbage may be written to brick_type.
380 */
381 int elsc_rack_bay_type_get( l1sc_t *sc, uint *rack,
382 uint *bay, uint *brick_type )
383 {
384 char msg[BRL1_QSIZE]; /* L1 request/response info */
385 int subch; /* system controller subchannel used */
386 int len; /* length of message */
387 uint32_t buf32; /* used to copy 32-bit rack & bay out of msg */
388
389 /* fill in msg with the opcode & params */
390 bzero( msg, BRL1_QSIZE );
391 if( (subch = sc_open( sc, L1_ADDR_LOCAL )) < 0 ) {
392 return ELSC_ERROR_CMD_SEND;
393 }
394
395 if( (len = sc_construct_msg( sc, subch, msg, BRL1_QSIZE,
396 L1_ADDR_TASK_GENERAL,
397 L1_REQ_RRBT, 0 )) < 0 )
398 {
399 sc_close( sc, subch );
400 return( ELSC_ERROR_CMD_ARGS );
401 }
402
403 /* send the request to the L1 */
404 if( SC_COMMAND( sc, subch, msg, msg, &len ) ) {
405 sc_close( sc, subch );
406 return( ELSC_ERROR_CMD_SEND );
407 }
408
409 /* free up subchannel */
410 sc_close( sc, subch );
411
412 /* check response */
413 if( sc_interpret_resp( msg, 4, L1_ARG_INT, &buf32,
414 L1_ARG_INT, brick_type ) < 0 )
415 {
416 return( ELSC_ERROR_RESP_FORMAT );
417 }
418
419 /* extract rack/bay info
420 *
421 * note that the 32-bit value returned by the L1 actually
422 * only uses the low-order sixteen bits for rack and bay
423 * information. A "normal" L1 address puts rack and bay
424 * information in bit positions 12 through 28. So if
425 * we initially shift the value returned 12 bits to the left,
426 * we can use the L1 addressing #define's to extract the
427 * values we need (see ksys/l1.h for a complete list of the
428 * various fields of an L1 address).
429 */
430 buf32 <<= L1_ADDR_BAY_SHFT;
431
432 *rack = (buf32 & L1_ADDR_RACK_MASK) >> L1_ADDR_RACK_SHFT;
433 *bay = (buf32 & L1_ADDR_BAY_MASK) >> L1_ADDR_BAY_SHFT;
434
435 /* convert brick_type to lower case */
436 *brick_type = *brick_type - 'A' + 'a';
437
438 return 0;
439 }
440
441
442 int elsc_module_get(elsc_t *e)
443 {
444 extern char brick_types[];
445 uint rnum, rack, bay, bricktype, t;
446 int ret;
447
448 /* construct module ID from rack and slot info */
449
450 if ((ret = elsc_rack_bay_type_get(e, &rnum, &bay, &bricktype)) < 0) {
451 return ret;
452 }
453
454 /* report unset location info. with a special, otherwise invalid modid */
455 if (rnum == 0 && bay == 0)
456 return MODULE_NOT_SET;
457
458 if (bay > MODULE_BPOS_MASK >> MODULE_BPOS_SHFT)
459 return ELSC_ERROR_MODULE;
460
461 /* Build a moduleid_t-compatible rack number */
462
463 rack = 0;
464 t = rnum / 100; /* rack class (CPU/IO) */
465 if (t > RACK_CLASS_MASK(rack) >> RACK_CLASS_SHFT(rack))
466 return ELSC_ERROR_MODULE;
467 RACK_ADD_CLASS(rack, t);
468 rnum %= 100;
469
470 t = rnum / 10; /* rack group */
471 if (t > RACK_GROUP_MASK(rack) >> RACK_GROUP_SHFT(rack))
472 return ELSC_ERROR_MODULE;
473 RACK_ADD_GROUP(rack, t);
474
475 t = rnum % 10; /* rack number (one-based) */
476 if (t-1 > RACK_NUM_MASK(rack) >> RACK_NUM_SHFT(rack))
477 return ELSC_ERROR_MODULE;
478 RACK_ADD_NUM(rack, t);
479
480 for( t = 0; t < MAX_BRICK_TYPES; t++ ) {
481 if( brick_types[t] == bricktype )
482 return RBT_TO_MODULE(rack, bay, t);
483 }
484
485 return ELSC_ERROR_MODULE;
486 }
487
488 int elsc_partition_set(elsc_t *e, int partition)
489 {
490 char msg[BRL1_QSIZE]; /* L1 request/response info */
491 int subch; /* system controller subchannel used */
492 int len; /* length of message */
493
494 /* fill in msg with the opcode & params */
495 bzero( msg, BRL1_QSIZE );
496 if( (subch = sc_open( e, L1_ADDR_LOCAL )) < 0 ) {
497 return ELSC_ERROR_CMD_SEND;
498 }
499
500 if( (len = sc_construct_msg( e, subch, msg, BRL1_QSIZE,
501 L1_ADDR_TASK_GENERAL,
502 L1_REQ_PARTITION_SET, 2,
503 L1_ARG_INT, partition )) < 0 )
504 {
505
506 sc_close( e, subch );
507 return( ELSC_ERROR_CMD_ARGS );
508 }
509
510 /* send the request to the L1 */
511 if( sc_command( e, subch, msg, msg, &len ) ) {
512 sc_close( e, subch );
513 return( ELSC_ERROR_CMD_SEND );
514 }
515
516 /* free up subchannel */
517 sc_close( e, subch );
518
519 /* check response */
520 if( sc_interpret_resp( msg, 0 ) < 0 )
521 {
522 return( ELSC_ERROR_RESP_FORMAT );
523 }
524
525 return( 0 );
526 }
527
528 int elsc_partition_get(elsc_t *e)
529 {
530 char msg[BRL1_QSIZE]; /* L1 request/response info */
531 int subch; /* system controller subchannel used */
532 int len; /* length of message */
533 uint32_t partition_id; /* used to copy partition id out of msg */
534
535 /* fill in msg with the opcode & params */
536 bzero( msg, BRL1_QSIZE );
537 if( (subch = sc_open( e, L1_ADDR_LOCAL )) < 0 ) {
538 return ELSC_ERROR_CMD_SEND;
539 }
540
541 if( (len = sc_construct_msg( e, subch, msg, BRL1_QSIZE,
542 L1_ADDR_TASK_GENERAL,
543 L1_REQ_PARTITION_GET, 0 )) < 0 )
544
545 {
546 sc_close( e, subch );
547 return( ELSC_ERROR_CMD_ARGS );
548 }
549
550 /* send the request to the L1 */
551 if( sc_command( e, subch, msg, msg, &len ) ) {
552 sc_close( e, subch );
553 return( ELSC_ERROR_CMD_SEND );
554 }
555
556 /* free up subchannel */
557 sc_close( e, subch );
558
559 /* check response */
560 if( sc_interpret_resp( msg, 2, L1_ARG_INT, &partition_id ) < 0 )
561 {
562 return( ELSC_ERROR_RESP_FORMAT );
563 }
564
565 return( partition_id );
566 }
567
568
569 /*
570 * elsc_cons_subch selects the "active" console subchannel for this node
571 * (i.e., the one that will currently receive input)
572 */
573 int elsc_cons_subch(elsc_t *e, uint ch)
574 {
575 char msg[BRL1_QSIZE]; /* L1 request/response info */
576 int subch; /* system controller subchannel used */
577 int len; /* length of message */
578
579 /* fill in msg with the opcode & params */
580 bzero( msg, BRL1_QSIZE );
581 subch = sc_open( e, L1_ADDR_LOCAL );
582
583 if( (len = sc_construct_msg( e, subch, msg, BRL1_QSIZE,
584 L1_ADDR_TASK_GENERAL,
585 L1_REQ_CONS_SUBCH, 2,
586 L1_ARG_INT, ch)) < 0 )
587 {
588 sc_close( e, subch );
589 return( ELSC_ERROR_CMD_ARGS );
590 }
591
592 /* send the request to the L1 */
593 if( SC_COMMAND( e, subch, msg, msg, &len ) ) {
594 sc_close( e, subch );
595 return( ELSC_ERROR_CMD_SEND );
596 }
597
598 /* free up subchannel */
599 sc_close( e, subch );
600
601 /* check response */
602 if( sc_interpret_resp( msg, 0 ) < 0 )
603 {
604 return( ELSC_ERROR_RESP_FORMAT );
605 }
606
607 return 0;
608 }
609
610
611 /*
612 * elsc_cons_node should only be executed by one node. It declares to
613 * the system controller that the node from which it is called will be
614 * the owner of the system console.
615 */
616 int elsc_cons_node(elsc_t *e)
617 {
618 char msg[BRL1_QSIZE]; /* L1 request/response info */
619 int subch; /* system controller subchannel used */
620 int len; /* length of message */
621
622 /* fill in msg with the opcode & params */
623 bzero( msg, BRL1_QSIZE );
624 subch = sc_open( e, L1_ADDR_LOCAL );
625
626 if( (len = sc_construct_msg( e, subch, msg, BRL1_QSIZE,
627 L1_ADDR_TASK_GENERAL,
628 L1_REQ_CONS_NODE, 0 )) < 0 )
629 {
630 sc_close( e, subch );
631 return( ELSC_ERROR_CMD_ARGS );
632 }
633
634 /* send the request to the L1 */
635 if( SC_COMMAND( e, subch, msg, msg, &len ) ) {
636 sc_close( e, subch );
637 return( ELSC_ERROR_CMD_SEND );
638 }
639
640 /* free up subchannel */
641 sc_close( e, subch );
642
643 /* check response */
644 if( sc_interpret_resp( msg, 0 ) < 0 )
645 {
646 return( ELSC_ERROR_RESP_FORMAT );
647 }
648
649 return 0;
650 }
651
652
653 /* elsc_display_line writes up to 12 characters to either the top or bottom
654 * line of the L1 display. line points to a buffer containing the message
655 * to be displayed. The zero-based line number is specified by lnum (so
656 * lnum == 0 specifies the top line and lnum == 1 specifies the bottom).
657 * Lines longer than 12 characters, or line numbers not less than
658 * L1_DISPLAY_LINES, cause elsc_display_line to return an error.
659 */
660 int elsc_display_line(elsc_t *e, char *line, int lnum)
661 {
662 char msg[BRL1_QSIZE];
663 int subch; /* system controller subchannel used */
664 int len; /* number of msg buffer bytes used */
665
666 /* argument sanity checking */
667 if( !(lnum < L1_DISPLAY_LINES) )
668 return( ELSC_ERROR_CMD_ARGS );
669 if( !(strlen( line ) <= L1_DISPLAY_LINE_LENGTH) )
670 return( ELSC_ERROR_CMD_ARGS );
671
672 /* fill in msg with the opcode & params */
673 bzero( msg, BRL1_QSIZE );
674 subch = sc_open( (l1sc_t *)e, L1_ADDR_LOCAL );
675
676 if( (len = sc_construct_msg( (l1sc_t *)e, subch, msg, BRL1_QSIZE,
677 L1_ADDR_TASK_GENERAL,
678 (L1_REQ_DISP1+lnum), 2,
679 L1_ARG_ASCII, line )) < 0 )
680 {
681 sc_close( e, subch );
682 return( ELSC_ERROR_CMD_ARGS );
683 }
684
685 /* send the request to the L1 */
686 if( SC_COMMAND( (l1sc_t *)e, subch, msg, msg, &len ) < 0 )
687 {
688 sc_close( e, subch );
689 return( ELSC_ERROR_CMD_SEND );
690 }
691
692 /* free up subchannel */
693 sc_close( (l1sc_t *)e, subch );
694
695 /* check response */
696 if( sc_interpret_resp( msg, 0 ) < 0 )
697 {
698 return( ELSC_ERROR_RESP_FORMAT );
699 }
700
701 return 0;
702 }
703
704
705 /* elsc_display_mesg silently drops message characters beyond the 12th.
706 */
707 int elsc_display_mesg(elsc_t *e, char *chr)
708 {
709
710 char line[L1_DISPLAY_LINE_LENGTH+1];
711 int numlines, i;
712 int result;
713
714 numlines = (strlen( chr ) + L1_DISPLAY_LINE_LENGTH - 1) /
715 L1_DISPLAY_LINE_LENGTH;
716
717 if( numlines > L1_DISPLAY_LINES )
718 numlines = L1_DISPLAY_LINES;
719
720 for( i = 0; i < numlines; i++ )
721 {
722 strncpy( line, chr, L1_DISPLAY_LINE_LENGTH );
723 line[L1_DISPLAY_LINE_LENGTH] = '\0';
724
725 /* generally we want to leave the first line of the L1 display
726 * alone (so the L1 can manipulate it). If you need to be able
727 * to display to both lines (for debugging purposes), define
728 * L1_DISP_2LINES in irix/kern/ksys/l1.h, or add -DL1_DISP_2LINES
729 * to your 'defs file.
730 */
731 #if defined(L1_DISP_2LINES)
732 if( (result = elsc_display_line( e, line, i )) < 0 )
733 #else
734 if( (result = elsc_display_line( e, line, i+1 )) < 0 )
735 #endif
736
737 return result;
738
739 chr += L1_DISPLAY_LINE_LENGTH;
740 }
741
742 return 0;
743 }
744
745
746 int elsc_password_set(elsc_t *e, char *password)
747 {
748 /* shush compiler */
749 e = e;
750 password = password;
751
752 /* fill in buffer with the opcode & params; call elsc_command */
753
754 return 0;
755 }
756
757 int elsc_password_get(elsc_t *e, char *password)
758 {
759 /* shush compiler */
760 e = e;
761 password = password;
762
763 /* fill in buffer with the opcode & params; call elsc_command */
764
765 return 0;
766 }
767
768
769 /*
770 * sc_portspeed_get
771 *
772 * retrieve the current portspeed setting for the bedrock II
773 */
774 int sc_portspeed_get(l1sc_t *sc)
775 {
776 char msg[BRL1_QSIZE];
777 int len; /* length of message being sent */
778 int subch; /* system controller subchannel used */
779 int portspeed_a, portspeed_b;
780 /* ioport clock rates */
781
782 bzero( msg, BRL1_QSIZE );
783 subch = sc_open( sc, L1_ADDR_LOCAL );
784
785 if( (len = sc_construct_msg( sc, subch, msg, BRL1_QSIZE,
786 L1_ADDR_TASK_GENERAL,
787 L1_REQ_PORTSPEED,
788 0 )) < 0 )
789 {
790 sc_close( sc, subch );
791 return( ELSC_ERROR_CMD_ARGS );
792 }
793
794 /* send the request to the L1 */
795 if( sc_command( sc, subch, msg, msg, &len ) < 0 )
796 {
797 sc_close( sc, subch );
798 return( ELSC_ERROR_CMD_SEND );
799 }
800
801 /* free up subchannel */
802 sc_close( sc, subch );
803
804 /* check response */
805 if( sc_interpret_resp( msg, 4,
806 L1_ARG_INT, &portspeed_a,
807 L1_ARG_INT, &portspeed_b ) < 0 )
808 {
809 return( ELSC_ERROR_RESP_FORMAT );
810 }
811
812 /* for the c-brick, we ignore the portspeed_b value */
813 return (portspeed_a ? 600 : 400);
814 }
815
816 /*
817 * elsc_power_query
818 *
819 * To be used after system reset, this command returns 1 if the reset
820 * was the result of a power-on, 0 otherwise.
821 *
822 * The power query status is cleared to 0 after it is read.
823 */
824
825 int elsc_power_query(elsc_t *e)
826 {
827 e = e; /* shush the compiler */
828
829 /* fill in buffer with the opcode & params; call elsc_command */
830
831 return 1;
832 }
833
834 int elsc_rpwr_query(elsc_t *e, int is_master)
835 {
836 /* shush the compiler */
837 e = e;
838 is_master = is_master;
839
840 /* fill in buffer with the opcode & params; call elsc_command */
841
842 return 0;
843 }
844
845 /*
846 * elsc_power_down
847 *
848 * Sets up system to shut down in "sec" seconds (or modifies the
849 * shutdown time if one is already in effect). Use 0 to power
850 * down immediately.
851 */
852
853 int elsc_power_down(elsc_t *e, int sec)
854 {
855 /* shush compiler */
856 e = e;
857 sec = sec;
858
859 /* fill in buffer with the opcode & params; call elsc_command */
860
861 return 0;
862 }
863
864
865 int elsc_system_reset(elsc_t *e)
866 {
867 char msg[BRL1_QSIZE];
868 int subch; /* system controller subchannel used */
869 int len; /* number of msg buffer bytes used */
870 int result;
871
872 /* fill in msg with the opcode & params */
873 bzero( msg, BRL1_QSIZE );
874 if( (subch = sc_open( e, L1_ADDR_LOCAL )) < 0 ) {
875 return ELSC_ERROR_CMD_SEND;
876 }
877
878 if( (len = sc_construct_msg( e, subch, msg, BRL1_QSIZE,
879 L1_ADDR_TASK_GENERAL,
880 L1_REQ_RESET, 0 )) < 0 )
881 {
882 sc_close( e, subch );
883 return( ELSC_ERROR_CMD_ARGS );
884 }
885
886 /* send the request to the L1 */
887 if( (result = sc_command( e, subch, msg, msg, &len )) ) {
888 sc_close( e, subch );
889 if( result == SC_NMSG ) {
890 /* timeout is OK. We've sent the reset. Now it's just
891 * a matter of time...
892 */
893 return( 0 );
894 }
895 return( ELSC_ERROR_CMD_SEND );
896 }
897
898 /* free up subchannel */
899 sc_close( e, subch );
900
901 /* check response */
902 if( sc_interpret_resp( msg, 0 ) < 0 )
903 {
904 return( ELSC_ERROR_RESP_FORMAT );
905 }
906
907 return 0;
908 }
909
910
911 int elsc_power_cycle(elsc_t *e)
912 {
913 /* shush compiler */
914 e = e;
915
916 /* fill in buffer with the opcode & params; call sc_command */
917
918 return 0;
919 }
920
921
922 /*
923 * L1 Support for reading
924 * cbrick uid.
925 */
926
927 int elsc_nic_get(elsc_t *e, uint64_t *nic, int verbose)
928 {
929 /* this parameter included only for SN0 compatibility */
930 verbose = verbose;
931
932 /* We don't go straight to the bedrock/L1 protocol on this one, but let
933 * the eeprom layer prepare the eeprom data as we would like it to
934 * appear to the caller
935 */
936 return cbrick_uid_get( e->nasid, nic );
937 }
938
939
940 int _elsc_hbt(elsc_t *e, int ival, int rdly)
941 {
942 e = e;
943 ival = ival;
944 rdly = rdly;
945
946 /* fill in buffer with the opcode & params; call elsc_command */
947
948 return 0;
949 }
950
951
952 /* send a command string to an L1 */
953 int sc_command_interp( l1sc_t *sc, l1addr_t compt, l1addr_t rack, l1addr_t bay,
954 char *cmd )
955 {
956 char msg[BRL1_QSIZE];
957 int len; /* length of message being sent */
958 int subch; /* system controller subchannel used */
959 l1addr_t target; /* target system controller for command */
960
961 /* fill in msg with the opcode & params */
962 bzero( msg, BRL1_QSIZE );
963
964 L1_BUILD_ADDR( &target, compt, rack, bay, 0 );
965 subch = sc_open( sc, target );
966
967 if( (len = sc_construct_msg( sc, subch, msg, BRL1_QSIZE,
968 L1_ADDR_TASK_CMD, L1_REQ_EXEC_CMD, 2,
969 L1_ARG_ASCII, cmd )) < 0 )
970 {
971 sc_close( sc, subch );
972 return( ELSC_ERROR_CMD_ARGS );
973 }
974
975 /* send the request to the L1 */
976 if( SC_COMMAND( sc, subch, msg, msg, &len ) < 0 )
977 {
978 sc_close( sc, subch );
979 return( ELSC_ERROR_CMD_SEND );
980 }
981
982 /* free up subchannel */
983 sc_close( sc, subch );
984
985 /* check response */
986 if( sc_interpret_resp( msg, 0 ) < 0 )
987 {
988 return( ELSC_ERROR_RESP_FORMAT );
989 }
990
991 return 0;
992 }
993
994 /*
995 * sc_power_down
996 *
997 * Shuts down the c-brick associated with sc, and any attached I/O bricks
998 * or other c-bricks (won't go through r-bricks).
999 */
1000
1001 int sc_power_down(l1sc_t *sc)
1002 {
1003 return sc_command_interp( sc, L1_ADDR_TYPE_L1, L1_ADDR_RACK_LOCAL,
1004 L1_ADDR_BAY_LOCAL, "* pwr d" );
1005 }
1006
1007
1008 /*
1009 * sc_power_down_all
1010 *
1011 * Works similarly to sc_power_down, except that the request is sent to the
1012 * closest L2 and EVERYBODY gets turned off.
1013 */
1014
1015 int sc_power_down_all(l1sc_t *sc)
1016 {
1017 if( nodepda->num_routers > 0 ) {
1018 return sc_command_interp( sc, L1_ADDR_TYPE_L2, L1_ADDR_RACK_LOCAL,
1019 L1_ADDR_BAY_LOCAL, "* pwr d" );
1020 }
1021 else {
1022 return sc_power_down( sc );
1023 }
1024 }
1025
1026
1027 /*
1028 * Routines for reading the R-brick's L1
1029 */
1030
1031 int router_module_get( nasid_t nasid, net_vec_t path )
1032 {
1033 uint rnum, rack, bay, t;
1034 int ret;
1035 l1sc_t sc;
1036
1037 /* prepare l1sc_t struct */
1038 sc_init( &sc, nasid, path );
1039
1040 /* construct module ID from rack and slot info */
1041
1042 if ((ret = elsc_rack_bay_get(&sc, &rnum, &bay)) < 0)
1043 return ret;
1044
1045 /* report unset location info. with a special, otherwise invalid modid */
1046 if (rnum == 0 && bay == 0)
1047 return MODULE_NOT_SET;
1048
1049 if (bay > MODULE_BPOS_MASK >> MODULE_BPOS_SHFT)
1050 return ELSC_ERROR_MODULE;
1051
1052 /* Build a moduleid_t-compatible rack number */
1053
1054 rack = 0;
1055 t = rnum / 100; /* rack class (CPU/IO) */
1056 if (t > RACK_CLASS_MASK(rack) >> RACK_CLASS_SHFT(rack))
1057 return ELSC_ERROR_MODULE;
1058 RACK_ADD_CLASS(rack, t);
1059 rnum %= 100;
1060
1061 t = rnum / 10; /* rack group */
1062 if (t > RACK_GROUP_MASK(rack) >> RACK_GROUP_SHFT(rack))
1063 return ELSC_ERROR_MODULE;
1064 RACK_ADD_GROUP(rack, t);
1065
1066 t = rnum % 10; /* rack number (one-based) */
1067 if (t-1 > RACK_NUM_MASK(rack) >> RACK_NUM_SHFT(rack))
1068 return ELSC_ERROR_MODULE;
1069 RACK_ADD_NUM(rack, t);
1070
1071 ret = RBT_TO_MODULE(rack, bay, MODULE_RBRICK);
1072 return ret;
1073 }
1074
1075
1076 /*
1077 * iobrick routines
1078 */
1079
1080 /* iobrick_rack_bay_type_get fills in the three int * arguments with the
1081 * rack number, bay number and brick type of the L1 being addressed. Note
1082 * that if the L1 operation fails and this function returns an error value,
1083 * garbage may be written to brick_type.
1084 */
1085 int iobrick_rack_bay_type_get( l1sc_t *sc, uint *rack,
1086 uint *bay, uint *brick_type )
1087 {
1088 char msg[BRL1_QSIZE]; /* L1 request/response info */
1089 int subch; /* system controller subchannel used */
1090 int len; /* length of message */
1091 uint32_t buf32; /* used to copy 32-bit rack & bay out of msg */
1092
1093 /* fill in msg with the opcode & params */
1094 bzero( msg, BRL1_QSIZE );
1095 if( (subch = sc_open( sc, L1_ADDR_LOCALIO )) < 0 ) {
1096 return( ELSC_ERROR_CMD_SEND );
1097 }
1098
1099 if( (len = sc_construct_msg( sc, subch, msg, BRL1_QSIZE,
1100 L1_ADDR_TASK_GENERAL,
1101 L1_REQ_RRBT, 0 )) < 0 )
1102 {
1103 sc_close( sc, subch );
1104 return( ELSC_ERROR_CMD_ARGS );
1105 }
1106
1107 /* send the request to the L1 */
1108 if( sc_command( sc, subch, msg, msg, &len ) ) {
1109 sc_close( sc, subch );
1110 return( ELSC_ERROR_CMD_SEND );
1111 }
1112
1113 /* free up subchannel */
1114 sc_close( sc, subch );
1115
1116 /* check response */
1117 if( sc_interpret_resp( msg, 4, L1_ARG_INT, &buf32,
1118 L1_ARG_INT, brick_type ) < 0 )
1119 {
1120 return( ELSC_ERROR_RESP_FORMAT );
1121 }
1122
1123 /* extract rack/bay info
1124 *
1125 * note that the 32-bit value returned by the L1 actually
1126 * only uses the low-order sixteen bits for rack and bay
1127 * information. A "normal" L1 address puts rack and bay
1128 * information in bit positions 12 through 28. So if
1129 * we initially shift the value returned 12 bits to the left,
1130 * we can use the L1 addressing #define's to extract the
1131 * values we need (see ksys/l1.h for a complete list of the
1132 * various fields of an L1 address).
1133 */
1134 buf32 <<= L1_ADDR_BAY_SHFT;
1135
1136 *rack = (buf32 & L1_ADDR_RACK_MASK) >> L1_ADDR_RACK_SHFT;
1137 *bay = (buf32 & L1_ADDR_BAY_MASK) >> L1_ADDR_BAY_SHFT;
1138
1139 return 0;
1140 }
1141
1142
1143 int iobrick_module_get(l1sc_t *sc)
1144 {
1145 uint rnum, rack, bay, brick_type, t;
1146 int ret;
1147
1148 /* construct module ID from rack and slot info */
1149
1150 if ((ret = iobrick_rack_bay_type_get(sc, &rnum, &bay, &brick_type)) < 0)
1151 return ret;
1152
1153 if (bay > MODULE_BPOS_MASK >> MODULE_BPOS_SHFT)
1154 return ELSC_ERROR_MODULE;
1155
1156 /* Build a moduleid_t-compatible rack number */
1157
1158 rack = 0;
1159 t = rnum / 100; /* rack class (CPU/IO) */
1160 if (t > RACK_CLASS_MASK(rack) >> RACK_CLASS_SHFT(rack))
1161 return ELSC_ERROR_MODULE;
1162 RACK_ADD_CLASS(rack, t);
1163 rnum %= 100;
1164
1165 t = rnum / 10; /* rack group */
1166 if (t > RACK_GROUP_MASK(rack) >> RACK_GROUP_SHFT(rack))
1167 return ELSC_ERROR_MODULE;
1168 RACK_ADD_GROUP(rack, t);
1169
1170 t = rnum % 10; /* rack number (one-based) */
1171 if (t-1 > RACK_NUM_MASK(rack) >> RACK_NUM_SHFT(rack))
1172 return ELSC_ERROR_MODULE;
1173 RACK_ADD_NUM(rack, t);
1174
1175 switch( brick_type ) {
1176 case 'I':
1177 brick_type = MODULE_IBRICK; break;
1178 case 'P':
1179 brick_type = MODULE_PBRICK; break;
1180 case 'X':
1181 brick_type = MODULE_XBRICK; break;
1182 }
1183
1184 ret = RBT_TO_MODULE(rack, bay, brick_type);
1185
1186 return ret;
1187 }
1188
1189 /* iobrick_get_sys_snum asks the attached iobrick for the system
1190 * serial number. This function will only be relevant to the master
1191 * cbrick (the one attached to the bootmaster ibrick); other nodes
1192 * may call the function, but the value returned to the master node
1193 * will be the one used as the system serial number by the kernel.
1194 */
1195
1196 int
1197 iobrick_get_sys_snum( l1sc_t *sc, char *snum_str )
1198 {
1199 char msg[BRL1_QSIZE]; /* L1 request/response info */
1200 int subch; /* system controller subchannel used */
1201 int len; /* length of message */
1202
1203 /* fill in msg with the opcode & params */
1204 bzero( msg, BRL1_QSIZE );
1205 if( (subch = sc_open( sc, L1_ADDR_LOCALIO )) < 0 ) {
1206 return( ELSC_ERROR_CMD_SEND );
1207 }
1208
1209 if( (len = sc_construct_msg( sc, subch, msg, BRL1_QSIZE,
1210 L1_ADDR_TASK_GENERAL,
1211 L1_REQ_SYS_SERIAL, 0 )) < 0 )
1212 {
1213 sc_close( sc, subch );
1214 return( ELSC_ERROR_CMD_ARGS );
1215 }
1216
1217 /* send the request to the L1 */
1218 if( sc_command( sc, subch, msg, msg, &len ) ) {
1219 sc_close( sc, subch );
1220 return( ELSC_ERROR_CMD_SEND );
1221 }
1222
1223 /* free up subchannel */
1224 sc_close( sc, subch );
1225
1226 /* check response */
1227 return( sc_interpret_resp( msg, 2, L1_ARG_ASCII, snum_str ) );
1228 }
1229
1230
1231 /*
1232 * The following functions apply (or cut off) power to the specified
1233 * pci bus or slot.
1234 */
1235
1236 int
1237 iobrick_pci_pwr( l1sc_t *sc, int bus, int slot, int req_code )
1238 {
1239 #if 0 /* The "bedrock request" method of performing this function
1240 * seems to be broken in the L1, so for now use the command-
1241 * interpreter method
1242 */
1243
1244 char msg[BRL1_QSIZE];
1245 int len; /* length of message being sent */
1246 int subch; /* system controller subchannel used */
1247
1248 /* fill in msg with the opcode & params */
1249 bzero( msg, BRL1_QSIZE );
1250 subch = sc_open( sc, L1_ADDR_LOCALIO );
1251
1252 if( (len = sc_construct_msg( sc, subch, msg, BRL1_QSIZE,
1253 L1_ADDR_TASK_GENERAL,
1254 req_code, 4,
1255 L1_ARG_INT, bus,
1256 L1_ARG_INT, slot )) < 0 )
1257 {
1258 sc_close( sc, subch );
1259 return( ELSC_ERROR_CMD_ARGS );
1260 }
1261
1262 /* send the request to the L1 */
1263 if( SC_COMMAND(sc, subch, msg, msg, &len ) < 0 )
1264 {
1265 sc_close( sc, subch );
1266 return( ELSC_ERROR_CMD_SEND );
1267 }
1268
1269 /* free up subchannel */
1270 sc_close( sc, subch );
1271
1272 /* check response */
1273 if( sc_interpret_resp( msg, 0 ) < 0 )
1274 {
1275 return( ELSC_ERROR_RESP_FORMAT );
1276 }
1277
1278 return 0;
1279
1280 #else
1281 char cmd[64];
1282 char *fxn;
1283
1284 switch( req_code )
1285 {
1286 case L1_REQ_PCI_UP:
1287 fxn = "u";
1288 break;
1289 case L1_REQ_PCI_DOWN:
1290 fxn = "d";
1291 break;
1292 case L1_REQ_PCI_RESET:
1293 fxn = "rst";
1294 break;
1295 default:
1296 return( ELSC_ERROR_CMD_ARGS );
1297 }
1298
1299 if( slot == -1 )
1300 sprintf( cmd, "pci %d %s", bus, fxn );
1301 else
1302 sprintf( cmd, "pci %d %d %s", bus, slot, fxn );
1303
1304 return sc_command_interp( sc, L1_ADDR_TYPE_IOBRICK,
1305 L1_ADDR_RACK_LOCAL, L1_ADDR_BAY_LOCAL, cmd );
1306 #endif
1307 }
1308
1309 int
1310 iobrick_pci_slot_pwr( l1sc_t *sc, int bus, int slot, int up )
1311 {
1312 return iobrick_pci_pwr( sc, bus, slot, up );
1313 }
1314
1315 int
1316 iobrick_pci_bus_pwr( l1sc_t *sc, int bus, int up )
1317 {
1318 return iobrick_pci_pwr( sc, bus, -1, up );
1319 }
1320
1321
1322 int
1323 iobrick_pci_slot_rst( l1sc_t *sc, int bus, int slot )
1324 {
1325 return iobrick_pci_pwr( sc, bus, slot, L1_REQ_PCI_RESET );
1326 }
1327
1328 int
1329 iobrick_pci_bus_rst( l1sc_t *sc, int bus )
1330 {
1331 return iobrick_pci_pwr( sc, bus, -1, L1_REQ_PCI_RESET );
1332 }
1333
1334
1335 /* get the L1 firmware version for an iobrick */
1336 int
1337 iobrick_sc_version( l1sc_t *sc, char *result )
1338 {
1339 char msg[BRL1_QSIZE];
1340 int len; /* length of message being sent */
1341 int subch; /* system controller subchannel used */
1342 int major, /* major rev number */
1343 minor, /* minor rev number */
1344 bugfix; /* bugfix rev number */
1345
1346 /* fill in msg with the opcode & params */
1347 bzero( msg, BRL1_QSIZE );
1348 subch = sc_open( sc, L1_ADDR_LOCALIO );
1349
1350 if( (len = sc_construct_msg( sc, subch, msg, BRL1_QSIZE,
1351 L1_ADDR_TASK_GENERAL,
1352 L1_REQ_FW_REV, 0 )) < 0 )
1353 {
1354 sc_close( sc, subch );
1355 return( ELSC_ERROR_CMD_ARGS );
1356 }
1357
1358 /* send the request to the L1 */
1359 if( SC_COMMAND(sc, subch, msg, msg, &len ) < 0 )
1360 {
1361 sc_close( sc, subch );
1362 return( ELSC_ERROR_CMD_SEND );
1363 }
1364
1365 /* free up subchannel */
1366 sc_close( sc, subch );
1367
1368 /* check response */
1369 if( sc_interpret_resp( msg, 6, L1_ARG_INT, &major,
1370 L1_ARG_INT, &minor, L1_ARG_INT, &bugfix )
1371 < 0 )
1372 {
1373 return( ELSC_ERROR_RESP_FORMAT );
1374 }
1375
1376 sprintf( result, "%d.%d.%d", major, minor, bugfix );
1377
1378 return 0;
1379 }
1380
1381
1382
1383 /* elscuart routines
1384 *
1385 * Most of the elscuart functionality is implemented in l1.c. The following
1386 * is directly "recycled" from elsc.c.
1387 */
1388
1389
1390 /*
1391 * _elscuart_puts
1392 */
1393
1394 int _elscuart_puts(elsc_t *e, char *s)
1395 {
1396 int c;
1397
1398 if (s == 0)
1399 s = "<NULL>";
1400
1401 while ((c = LBYTE(s)) != 0) {
1402 if (_elscuart_putc(e, c) < 0)
1403 return -1;
1404 s++;
1405 }
1406
1407 return 0;
1408 }
1409
1410
1411 /*
1412 * elscuart wrapper routines
1413 *
1414 * The following routines are similar to their counterparts in l1.c,
1415 * except instead of taking an elsc_t pointer directly, they call
1416 * a global routine "get_elsc" to obtain the pointer.
1417 * This is useful when the elsc is employed for stdio.
1418 */
1419
1420 int elscuart_probe(void)
1421 {
1422 return _elscuart_probe(get_elsc());
1423 }
1424
1425 void elscuart_init(void *init_data)
1426 {
1427 _elscuart_init(get_elsc());
1428 /* dummy variable included for driver compatability */
1429 init_data = init_data;
1430 }
1431
1432 int elscuart_poll(void)
1433 {
1434 return _elscuart_poll(get_elsc());
1435 }
1436
1437 int elscuart_readc(void)
1438 {
1439 return _elscuart_readc(get_elsc());
1440 }
1441
1442 int elscuart_getc(void)
1443 {
1444 return _elscuart_getc(get_elsc());
1445 }
1446
1447 int elscuart_puts(char *s)
1448 {
1449 return _elscuart_puts(get_elsc(), s);
1450 }
1451
1452 int elscuart_putc(int c)
1453 {
1454 return _elscuart_putc(get_elsc(), c);
1455 }
1456
1457 int elscuart_flush(void)
1458 {
1459 return _elscuart_flush(get_elsc());
1460 }
1461