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