1 /*-
2 * @(#)if_acp.c 7.3 (Berkeley) 12/16/90
3 */
4
5 /*************************************************************************/
6 /* */
7 /* */
8 /* ________________________________________________________ */
9 /* / \ */
10 /* | AAA CCCCCCCCCCCCCC CCCCCCCCCCCCCC | */
11 /* | AAAAA CCCCCCCCCCCCCCCC CCCCCCCCCCCCCCCC | */
12 /* | AAAAAAA CCCCCCCCCCCCCCCCC CCCCCCCCCCCCCCCCC | */
13 /* | AAAA AAAA CCCC CCCC | */
14 /* | AAAA AAAA CCCC CCCC | */
15 /* | AAAA AAAA CCCC CCCC | */
16 /* | AAAA AAAA CCCC CCCC | */
17 /* | AAAA AAAAAAAAAAA CCCCCCCCCCCCCCCCC CCCCCCCCCCCCCCCCC | */
18 /* | AAAA AAAAAAAAAAA CCCCCCCCCCCCCCCC CCCCCCCCCCCCCCCC | */
19 /* | AAAA AAAAAAAAA CCCCCCCCCCCCCC CCCCCCCCCCCCCC | */
20 /* \________________________________________________________/ */
21 /* */
22 /* Copyright (c) 1985 by Advanced Computer Communications */
23 /* 720 Santa Barbara Street, Santa Barbara, California 93101 */
24 /* (805) 963-9431 */
25 /* */
26 /* */
27 /* File: if_acp.c */
28 /* */
29 /* Author: Arthur Berggreen */
30 /* */
31 /* Project: ACP6100 (UPB with HDLC firmware) */
32 /* */
33 /* Function: 4.2BSD UNIX Network Interface Driver for ACP6100 */
34 /* */
35 /* Components: if_acp.c, if_acpreg.h, if_acpvar.h */
36 /* */
37 /* Revision History: */
38 /* */
39 /* 16-AUG-1985 Clare Russ: add fileheader and comments */
40 /* 24-SEP-1985 Clare Russ: modify for socket ioctl user interface */
41 /* 06-NOV-1985 Clare Russ: modify for socket ioctl under TWG */
42 /* 11-NOV-1985 Clare Russ: Add a call to acpreset() in acpioctl() */
43 /* before processing socket ioctl to clear COMREGs. In the */
44 /* acpinit() routine, avoid redundant allocation of UMRs by */
45 /* doing so only if the front end is not RUNNING. */
46 /* 14-NOV-1985 Clare Russ: Trace if_ubainit failure: happens with */
47 /* TWG, not 4.2BSD. */
48 /* 21-NOV-1985 Clare Russ: Modify for compliance with the new */
49 /* Control Interface (CIF) and Access Path Allocation Protocol */
50 /* (APAP). The CIF requires that Control Interface Messages */
51 /* (CIMs) are exchanged between the host and front end in */
52 /* command/response pairs. The APAP requires that the control */
53 /* and data paths be established (via exchange of CIMs between */
54 /* the host and the front end) prior to use. */
55 /* 26-NOV-1985 Clare Russ: Add ability to bring down line in */
56 /* response to 'acpconfig' command. */
57 /* 27-NOV-1985 Clare Russ: Add ability to specify DTE or DCE mode */
58 /* in response to 'acpconfig' command. */
59 /* 02-DEC-1985 Clare Russ: Add ability to set baud rate (external */
60 /* clock) or set internal clock. */
61 /* 14-JAN-1986 Clare Russ: Add acpinit call to acpioctl under */
62 /* SIOCSIFADDR processing */
63 /* 21-JAN-1986 Clare Russ: Flush pending I/O in acpreset, free the */
64 /* mbufs */
65 /* 30-MAY-1986 Clare Russ: Update MPCP host request subfunction */
66 /* values, fix baud rate values in baud_rate[], change default */
67 /* clock source from internal to external (in ssp_msg[]) */
68 /* 24-JUL-1986 Clare Russ: In supr_msg() print out RSF field when */
69 /* path allocation or deallocation fails */
70 /* 23-FEB-1987 Jeff Berkowitz: port to 4.3BSD by adding #ifdefs for */
71 /* new interface address formats, trapping 0 length mbufs, etc. */
72 /* 08-JAN-1988 Brad Engstrom: port to ULTRIX 2.0 by using the */
73 /* UBAUVII (ultrix 2.0) and MVAX (microvax) defines to handle */
74 /* special cases. These cases are: */
75 /* 1) not declaring br, cvec as value-result in the probe routine*/
76 /* 2) using 0x17 as the ipl for a microvax */
77 /* 3) in all other cases the ULTRIX drivers behaves like a 4.3 */
78 /* driver. */
79 /* */
80 /* Usage Notes: */
81 /* */
82 /* device acp0 at uba0 csr 016700 flags 0 vector acpinta acpintb */
83 /* */
84 /* The 'flags' value is nonzero in the configuration file */
85 /* for TWG, and may be left as zero in the configuration */
86 /* file for UNIX 4.2 BSD. */
87 /* */
88 /* Application Notes: */
89 /* */
90 /* Refer to the Installation Instructions and the UNIX Programmer's */
91 /* Manual page which are on the driver distribution medium. */
92 /* */
93 /* */
94 /*************************************************************************/
95
96
97 /* #define ACPDEBUG 1 /* define for debug printf statements */
98
99 #ifdef ACPDEBUG
100 int acp_debug = 0; /* acp_debug is 1-8 for increasing verbosity */
101 #endif ACPDEBUG
102
103
104 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
105 /*%% %%*/
106 /*%% INCLUDE FILES %%*/
107 /*%% %%*/
108 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
109
110 /* The number of ACP 6100s in the system is defined in the configuration */
111 /* file in /sys/conf. When 'config' is run, the file acp.h is created */
112 /* with the definition of NACP, the number of ACP 6100s in the system. */
113
114 #include "acp.h"
115 #if NACP > 0
116 #include "../include/pte.h"
117
118 #include "sys/param.h"
119 #include "sys/systm.h"
120 #include "sys/mbuf.h"
121 #include "sys/buf.h"
122 #include "sys/protosw.h"
123 #include "sys/socket.h"
124 #include "sys/vmmac.h"
125 #include "sys/errno.h"
126 #include "sys/time.h"
127 #include "sys/kernel.h"
128 #include "sys/ioctl.h"
129
130 #include "net/if.h"
131 #include "net/netisr.h"
132 #include "net/route.h"
133 #include "netinet/in.h"
134 #include "netinet/in_systm.h"
135 #ifndef FOURTWO
136 # include "netinet/in_var.h"
137 #endif
138 #include "netinet/ip.h"
139 #include "netinet/ip_var.h"
140
141 #include "../include/cpu.h"
142 #include "../include/mtpr.h"
143 #include "../if/if_acpreg.h"
144 #include "../if/if_acpvar.h"
145 #include "../if/if_uba.h"
146 #include "../uba/ubareg.h"
147 #include "../uba/ubavar.h"
148
149
150 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
151 /*%% %%*/
152 /*%% GLOBAL FUNCTIONS %%*/
153 /*%% %%*/
154 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
155
156 int acpprobe();
157 int acpattach();
158 int acpreset();
159 int acpinit();
160 int acpoutput();
161 int acptimer(); /* currently no timer routine exists */
162 int acpioctl();
163 int acpinta();
164 int acpintb();
165 int acpstart();
166
167 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
168 /*%% %%*/
169 /*%% LOCAL FUNCTIONS %%*/
170 /*%% %%*/
171 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
172
173 static void acp_alloc(); /* allocate control and data paths */
174 static void acp_init(); /* send Set System Parameters Message */
175 static void acp_iorq();
176 static void start_chn();
177 static void acp_data();
178 static void acp_response(); /* send CIM response to the front end */
179 static void acp_supr();
180 static void supr_msg();
181 static void send_supr();
182
183 #ifdef ACPDEBUG
184 static void prt_addr();
185 static void prt_bytes();
186 #endif ACPDEBUG
187
188 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
189 /*%% %%*/
190 /*%% LOCAL VARIABLES %%*/
191 /*%% %%*/
192 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
193
194 struct uba_device *acpinfo[NACP]; /* ptrs to device info */
195 u_short acpstd[] = { 0767000, 0 }; /* standard UNIBUS CSR addresses */
196 struct uba_driver acpdriver = /* device driver info */
197 {
198 acpprobe, /* device probe routine */
199 0, /* slave probe routine */
200 acpattach, /* device attach routine */
201 0, /* "dmago" routine */
202 acpstd, /* device address */
203 "acp", /* device name */
204 acpinfo /* ptr to device info ptrs */
205 };
206
207 /* The alloc_msg array contains the Command Interface Message (CIM) */
208 /* for path allocation. There are 12 bytes of header followed by 6 */
209 /* bytes of command information */
210
211 static u_char alloc_msg[] =
212 {
213 0x00, /* reserved, must be zero */
214 FAC_ALLOC, /* front end ALLOC facility */
215 0x00, /* reserved, must be zero */
216 CMD_ALLOC, /* allocate path command */
217 0x0f, 0x0a, 0x0c, 0x0e, /* Command ID (CID) */
218 0x00, 0x00, 0x00, 0x00, /* Response/Status Field (RSF) */
219 0x00, ACP_SUPR, /* Data Path Number (DPN) */
220 0x00, FAC_HDLC, /* front end HDLC facility */
221 0x00, TYPE_CNTL /* type of path: control */
222 };
223
224
225 /* The dealloc_msg array contains the Command Interface Message (CIM) */
226 /* for path deallocation. There are 12 bytes of header followed by 2 */
227 /* bytes of command information */
228
229 static u_char dealloc_msg[] =
230 {
231 0x00, /* reserved, must be zero */
232 FAC_ALLOC, /* front end ALLOC facility */
233 0x00, /* reserved, must be zero */
234 CMD_DEALLOC, /* allocate path command */
235 0x0c, 0x0a, 0x0f, 0x0e, /* Command ID (CID) */
236 0x00, 0x00, 0x00, 0x00, /* Response/Status Field (RSF) */
237 0x00, ACP_SUPR, /* Data Path Number (DPN) */
238 };
239
240
241 /* Table of baud rate values and the associated parameter for the Set */
242 /* System Parameters message, ssp_msg. The second byte is nonzero for */
243 /* valid baud rate divisors. */
244
245 struct baud {
246 char b_value;
247 u_char parameter1; /* first byte of baud rate setting */
248 u_char parameter2; /* second byte of baud rate setting */
249 } baud_rate[] = {
250 { 1, 0x00, 0x02 },
251 { 2, 0x00, 0x03 },
252 { 3, 0x00, 0x04 },
253 { 4, 0x00, 0x08 },
254 { 5, 0x00, 0x10 },
255 { 6, 0x00, 0x28 },
256 { 7, 0x00, 0x3e },
257 { 8, 0x00, 0x47 },
258 { 9, 0x00, 0x85 },
259 { 10, 0x00, 0xd0 },
260 { 11, 0x01, 0xa1 },
261 { 12, 0x03, 0x41 },
262 { 13, 0x06, 0x83 },
263 { 14, 0x0d, 0x05 },
264 { 0, 0, 0 },
265 };
266
267 /* The ssp_msg array contains the Command Interface Message (CIM) for */
268 /* Setting HDLC System Paramters. There are 12 bytes of header */
269 /* followed by the line number and parameter modification commands */
270 /* (PMCs). The driver sends this CIM to the front end when kicked by */
271 /* the acpconfig program (via socket ioctl). In future versions, the */
272 /* CIM won't be here in the driver, it will be passed to the driver. */
273
274 u_char ssp_msg[] =
275 {
276 0x00, /* reserved, must be zero */
277 FAC_HDLC, /* front end HDLC facility */
278 0x00, /* reserved, must be zero */
279 CMD_SSP, /* set HDCL system parameters */
280 0x0b, 0x0e, 0x0e, 0x0f, /* Command ID (CID) */
281 0x00, 0x00, 0x00, 0x00, /* Response/Status Field (RSF) */
282 0x00, 0x00, /* HDLC Line Number (0) */
283 LINK_DISABLE, /* link disable */
284 LINK_LOOPBACK, /* loopback mode */
285 LOOP_EXTERNAL, /* external loopback */
286 DCE_OR_DTE, /* specify DTE or DCE mode */
287 DTE_MODE, /* DTE mode */
288 BAUD_CNTL, /* baud rate divisor */
289 0x00, /* */
290 0x03, /* 3 = 1.333 Mb/sec */
291 IDLE_POLL, /* idle poll selection */
292 0x01, /* 1 = on */
293 CLOCK_CNTL, /* xmit clock selection */
294 0x00, /* 0 = external source */
295 LINK_ENABLE /* link enable */
296 };
297
298 /* The response_msg array contains the Command Interface Message (CIM) */
299 /* response to be sent back to the front end in response to a CIM */
300 /* command for Frame Level Status from the front end. The front end */
301 /* sends the Frame Level Status CIM command to the host when the frame */
302 /* level status changes from up to down or vice versa. In keeping */
303 /* with the philosophy with CIMs, they are always exchanged in command */
304 /* response pairs. */
305
306 static u_char response_msg[] =
307 {
308 0x00, /* reserved, must be zero */
309 FAC_HDLC, /* front end HDLC facility */
310 0x00, /* reserved, must be zero */
311 RSP_FLUP, /* Frame Level Status */
312 0x00, 0x00, 0x00, 0x00, /* Command ID (CID) */
313 0x00, 0x00, 0x00, 0x00, /* RSF is 0 for success */
314 0x00, 0x00 /* HDLC Line Number (0) */
315 };
316
317
318 /***********************************************************************\
319 * *
320 * Information for each device unit is maintained in an array *
321 * of structures named acp_softc[]. The array is indexed by *
322 * unit number. Each entry includes the network interface *
323 * structure (acp_if) used by the routing code to locate the *
324 * interface, an array of Logical Channel control blocks which *
325 * maintain information about each of the Logical Channels (LCNs) *
326 * through which communication with the ACP is maintained, a queue *
327 * of I/O requests pending for the ACP, the UNIBUS interrupt *
328 * vector for the unit and misc flags. The Logical Channel *
329 * Control blocks maintain information about the state of each *
330 * LCN, a queue of outbound data, Half Duplex Channel (HDX) blocks *
331 * used for queuing I/O requests to the ACP and an ifuba *
332 * structure which records the UNIBUS resources being held by *
333 * the LCN. *
334 * *
335 \***********************************************************************/
336
337 struct sioq /* Start I/O queue head */
338 {
339 struct hdx_chan *sq_head; /* queue head */
340 struct hdx_chan *sq_tail; /* queue tail */
341 };
342
343 struct hdx_chan /* HDX channel block */
344 {
345 struct hdx_chan *hc_next; /* link to next HDX channel */
346 u_char hc_chan; /* HDX channel number */
347 u_char hc_adx; /* address bits 17-16 */
348 u_short hc_addr; /* address bits 15-00 */
349 u_short hc_cnt; /* byte count */
350 u_char hc_func; /* I/O function */
351 u_char hc_sbfc; /* I/O subfunction */
352 };
353
354 struct acp_cb /* Logical Channel control block */
355 {
356 u_char dc_lcn; /* LCN number */
357 struct ifqueue dc_oq; /* LCN output queue */
358 struct hdx_chan dc_rchan; /* LCN read HDX channel */
359 struct hdx_chan dc_wchan; /* LCN write HDX channel */
360 struct ifuba dc_ifuba; /* UNIBUS resources */
361 u_short dc_flags; /* misc flags */
362 };
363
364 struct acp_softc /* device control structure */
365 {
366 struct ifnet acp_if; /* network-visible interface */
367 struct acp_cb acp_cb[NACPCH+1]; /* Logical Channel cntl blks */
368 struct sioq acp_sioq; /* start I/O queue */
369 u_short acp_vector; /* UNIBUS interrupt vector */
370 u_short acp_flags; /* ACP operational flag */
371 u_char acp_path; /* path allocation flag */
372 u_short acp_maxout; /* maximum IP message sent */
373 u_short acp_maxin; /* maximum IP message rcvd */
374 #ifndef FOURTWO
375 struct in_addr acp_ipaddr; /* local IP address */
376 #endif
377 } acp_softc[NACP];
378
379 /* The acp_path flag indicates whether or not a path has been allocated */
380 /* and also whether or not to call acp_init to send an ssp_msg to the */
381 /* front end: acp_path = 1 indicates supervisory path is allocated */
382 /* acp_path = 2 indicates data path is allocated */
383 /* acp_path = 0x10 indicates acp_init should be called */
384 /* to send CIM ssp_msg to the front end */
385
386 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
387 /*%% %%*/
388 /*%% GLOBAL ROUTINES %%*/
389 /*%% %%*/
390 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
391
392 /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
393 /*%% ACPPROBE() %%*/
394 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
395 /* */
396 /* Purpose: */
397 /* */
398 /* This routine probes the device to obtain the UNIBUS interrupt */
399 /* vector. Since the ACP is a soft vector device, we obtain an */
400 /* unused vector from the uba structure and return that. The ACP */
401 /* is given the vector and the board is reset. In order to save */
402 /* the vector in the device info structure, we place it in a */
403 /* static temporary where the attach routine can find it and save */
404 /* it in the device info structure. This is necessary because */
405 /* probe only provides a pointer to the device and we have no */
406 /* idea which unit is being referenced. This works in 4.2BSD */
407 /* because the attach routine is called immediately after a */
408 /* successful probe. */
409 /* */
410 /* Call: acpprobe(reg) */
411 /* Argument: reg: caddr_t address in virtual memory of the */
412 /* control-status register */
413 /* Returns: length of register structure for ACP device */
414 /* Called by: network software, part of autoconfiguration on */
415 /* the VAX, the address of this routine is one of */
416 /* the fields of the uba_driver structure */
417 /* Calls to: nothing */
418 /* */
419 /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
420
421 static int savevec; /* static variable for vector */
422
acpprobe(reg,ui)423 acpprobe(reg, ui)
424 caddr_t reg;
425 struct uba_device *ui; /* TWG VAX/VMS ONLY! */
426 {
427 #ifndef UBAUVII /* not for Ultrix 2.0 */
428 register int br, cvec; /* r11, r10 value-result */
429 #endif UBAUVII
430 register struct acpregs *addr = (struct acpregs *)reg;
431
432 #ifdef lint
433 br = 0; cvec = br; br = cvec; /* these variables are value-result */
434 #endif
435
436 #ifdef VAXVMS
437 cvec = savevec = ui->ui_flags & 0x1f8; /* use flags from config file */
438 #else
439 cvec = savevec = (uba_hd[numuba].uh_lastiv - 8) & ~7;
440 uba_hd[numuba].uh_lastiv = cvec;
441 #endif VAXVMS
442
443 /* return a vector pair */
444 /* aligned on QUADWORD boundary */
445
446 /* cvec is the interrupt vector */
447 /* address on the UNIBUS */
448
449 /* br is the IPL of the device */
450 /* when it interrupts */
451
452 #ifdef MVAX
453 br = 0x17; /* return bus level for a uVAX */
454 #else
455 br = 0x15; /* return bus level */
456 #endif MVAX
457
458 addr->req_flags = 0; /* clear handshake flags */
459 addr->cmp_flags = 0;
460 addr->xfr_flags = 0;
461 addr->sys_stat = 0;
462 addr->sys_vect = cvec >> 2; /* pass vector to ACP */
463 addr->csr = CSR_RESET; /* reset the board */
464 addr->csr |= CSR_IENB; /* enable status intr */
465
466 return (sizeof(struct acpregs));
467 }
468
469 /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
470 /*%% ACPATTACH() %%*/
471 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
472 /* */
473 /* Purpose: */
474 /* */
475 /* This routine attaches the device to the network software. The */
476 /* network interface structure is filled in. The device will be */
477 /* initialized when the system is ready to accept packets. */
478 /* */
479 /* Call: acpattach(ui) */
480 /* Argument: ui: ptr to the uba_device data structure */
481 /* Returns: nothing */
482 /* Called by: network software, part of network system */
483 /* configuration, identification to the network */
484 /* software, the address of this routine is one */
485 /* of the fields of the uba_driver sturcture */
486 /* Calls to: if_attach() */
487 /* */
488 /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
489
490 acpattach(ui)
491 struct uba_device *ui;
492 {
493 register struct acp_softc *ds = &acp_softc[ui->ui_unit];
494
495 ds->acp_vector = savevec; /* save vector from probe() */
496 ds->acp_if.if_unit = ui->ui_unit; /* set unit number */
497 ds->acp_if.if_name = "acp"; /* set device name */
498 ds->acp_if.if_mtu = ACPMTU; /* set max msg size */
499 ds->acp_if.if_init = acpinit; /* set init routine addr */
500 ds->acp_if.if_ioctl = acpioctl; /* set ioctl routine addr */
501 ds->acp_if.if_output = acpoutput; /* set output routine addr */
502 ds->acp_if.if_start = acpstart; /* set start routine addr */
503 ds->acp_if.if_reset = acpreset; /* set reset routine addr */
504 if_attach(&ds->acp_if); /* attach new network device */
505 /* add to list of "active" */
506 /* interfaces, the argument */
507 /* passed locates the ifnet */
508 /* data structure */
509 }
510
511
512 /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
513 /*%% ACPRESET() %%*/
514 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
515 /* */
516 /* Purpose: */
517 /* */
518 /* Reset of interface after UNIBUS reset. If interface is on */
519 /* specified uba, reset its state. */
520 /* */
521 /* Call: acpreset(unit, uban) */
522 /* Arguments: unit: ACP device unit number */
523 /* uban: UNIBUS adapter number */
524 /* Returns: nothing */
525 /* Called by: network software, address of routine is */
526 /* defined in acp_if network interface struct */
527 /* Calls to: printf() */
528 /* IF_DEQUEUE() */
529 /* m_freem() */
530 /* */
531 /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
532
acpreset(unit,uban)533 acpreset(unit, uban)
534 int unit, uban;
535 {
536 register struct uba_device *ui; /* per "device" structure */
537 register struct acpregs *addr; /* ACP device register struct */
538 register struct acp_cb *dc;
539 register struct mbuf *m;
540 register int lcn;
541
542 if (unit >= NACP || (ui = acpinfo[unit]) == 0 || ui->ui_alive == 0 ||
543 ui->ui_ubanum != uban)
544 return;
545
546 printf("acp%d\n", unit);
547
548 addr = (struct acpregs *)ui->ui_addr; /* address of device in I/O space */
549
550 addr->req_flags = 0; /* clear handshake flags, mailbox */
551 /* flags for I/O requests */
552 addr->cmp_flags = 0; /* mailbox flags for I/O completion */
553 addr->xfr_flags = 0; /* mailbox flags for I/O transfer */
554 /* requests */
555 addr->sys_stat = 0; /* mailbox flags for system status */
556 addr->sys_vect = acp_softc[unit].acp_vector >> 2; /* pass base interrupt */
557 /* vector to ACP */
558 addr->csr = CSR_RESET; /* reset the board */
559 addr->csr |= CSR_IENB; /* enable status intr */
560 acp_softc[unit].acp_flags = 0; /* clear ACP operational flag */
561 acp_softc[unit].acp_path = 0; /* clear path allocation flag */
562
563 dc = acp_softc[unit].acp_cb; /* flush any queued output data */
564 for(lcn = 0; lcn <= NACPCH; lcn++) /* for all LCN's ... */
565 {
566 while(dc->dc_oq.ifq_len)
567 {
568 IF_DEQUEUE(&dc->dc_oq, m);
569 m_freem(m);
570 }
571 dc++;
572 }
573
574 }
575
576 /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
577 /*%% ACPINIT() %%*/
578 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
579 /* */
580 /* Purpose: */
581 /* */
582 /* This routine initializes the interface for operation. The */
583 /* device control blocks are initialized, UNIBUS resources are */
584 /* allocated and an initialization message is sent to the ACP. */
585 /* */
586 /* Call: acpinit(unit) */
587 /* Argument: unit: ACP device unit number */
588 /* Returns: nothing */
589 /* Called by: network software, address of this routine is */
590 /* defined in acp_if network interface struct */
591 /* acpioctl() */
592 /* acpintb() */
593 /* Calls to: in_netof() return the network number from */
594 /* internet address */
595 /* if_ubainit() */
596 /* btoc() */
597 /* splimp() */
598 /* acp_ioreq() */
599 /* acp_alloc() */
600 /* acp_init() */
601 /* splx() */
602 /* if_rtinit() */
603 /* */
604 /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
605
acpinit(unit)606 acpinit(unit)
607 int unit;
608 {
609 register struct acp_softc *ds = &acp_softc[unit];
610 register struct acp_cb *dc;
611 register struct uba_device *ui = acpinfo[unit];
612 #ifdef FOURTWO
613 struct sockaddr_in *sin;
614 #else
615 struct ifaddr *ifa = ds->acp_if.if_addrlist;
616 #endif
617 int lcn, s;
618
619 #ifdef ACPDEBUG
620 if (acp_debug > 0)
621 {
622 printf("acp%d: acpinit()\n", unit);
623 }
624 #endif ACPDEBUG
625
626 #ifdef FOURTWO
627 sin = (struct sockaddr_in *)&ds->acp_if.if_addr;
628 if (in_netof(sin->sin_addr) == 0)
629 #else
630 ifa = ds->acp_if.ifaddrlist;
631 #ifdef AF_LINK
632 for (; ifa; ifa = ifa->ifa_next)
633 if (ifa->ifa_addr->sa_family != AF_LINK)
634 break;
635 #endif
636 if ( ifa == 0) /* if we have no internet addr */
637 #endif
638 return;
639 if ((ds->acp_flags & ACPF_OK) == 0) /* or if ACP not operational */
640 return; /* don't init */
641
642
643 dc = ds->acp_cb; /* setup ptr to first LCN cntl block */
644
645 for(lcn=ACP_ALLOC;lcn<=NACPCH;lcn++) /* for all LCN's ... */
646 {
647 dc->dc_lcn = lcn; /* record LCN */
648
649 /* init LCN output queue */
650
651 dc->dc_oq.ifq_head = (struct mbuf *)0;
652 dc->dc_oq.ifq_tail = (struct mbuf *)0;
653 dc->dc_oq.ifq_len = 0;
654 dc->dc_oq.ifq_maxlen = ACP_OQMAX;
655 dc->dc_oq.ifq_drops = 0;
656
657 /* init HDX channels */
658
659 dc->dc_rchan.hc_next = (struct hdx_chan *)0;
660 dc->dc_rchan.hc_chan = lcn * 2;
661 dc->dc_wchan.hc_next = (struct hdx_chan *)0;
662 dc->dc_wchan.hc_chan = (lcn * 2) + 1;
663
664 /* init UNIBUS resources, allocate UNIBUS map registers */
665
666 if ((ds->acp_if.if_flags & IFF_RUNNING) == 0)
667 {
668 if (if_ubainit(&dc->dc_ifuba, ui->ui_ubanum,
669 0, (int)btoc(ACPMTU)) == 0)
670 {
671 printf("acp%d: failed getting UBA resources for lcn %d\n",
672 unit, lcn);
673 ds->acp_if.if_flags &= ~(IFF_RUNNING | IFF_UP);
674 return;
675 }
676 }
677 dc->dc_flags = 0; /* initialize flags */
678
679 dc++; /* point at next cntl blk */
680 }
681
682 ds->acp_sioq.sq_head = (struct hdx_chan *)0;
683 ds->acp_sioq.sq_tail = (struct hdx_chan *)0;
684 ds->acp_if.if_flags |= IFF_RUNNING;
685
686 s = splimp(); /* disable interrupts */
687
688 dc = ds->acp_cb; /* setup ptr to first LCN cntl block */
689
690 for(lcn=ACP_ALLOC;lcn<=NACPCH;lcn++) /* issue reads on all LCNs */
691 {
692 acp_iorq(ds, dc, ACPMTU, ACPRED+ACPSTR);
693 dc++;
694 }
695
696 /* if not already established, allocate control and data paths */
697
698 if ((ds->acp_path & ACP_SUPR) == 0)
699 acp_alloc(ds, TYPE_CNTL); /* allocate control path */
700 if ((ds->acp_path & ACP_DATA) == 0)
701 acp_alloc(ds, TYPE_DATA); /* allocate data path */
702
703 if ((ds->acp_path & INIT_OK) == INIT_OK)
704 {
705 acp_init(ds); /* init the ACP, if ioctl to do so */
706 ds->acp_path &= ~INIT_OK; /* turn off flag for acpinit() */
707 }
708
709 splx(s); /* enable interrupts */
710
711 #ifdef FOURTWO
712 if_rtinit(&ds->acp_if, RTF_UP); /* initialize the routing table entry */
713 /* according to the network, args */
714 /* are the addr of the ifnet struct */
715 /* and RTF_UP means the route is */
716 /* useable */
717 #endif
718 }
719
720 /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
721 /*%% ACPOUTPUT() %%*/
722 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
723 /* */
724 /* Purpose: */
725 /* */
726 /* This routine is called by the network software when it has an */
727 /* IP datagram to send out this interface. The datagtram is */
728 /* queued for output on that LCN. */
729 /* */
730 /* Call: acpoutput(ifp, m0, dst) */
731 /* Arguments: ifp: locates the network interface, ifnet */
732 /* m0: locates an mbuf buffer */
733 /* dst: is the socket destination address */
734 /* Returns: 0 for success, or one of following nonzero */
735 /* error indications: */
736 /* ENETDOWN */
737 /* EAFNOSUPPORT */
738 /* ENOBUFS */
739 /* Called by: network software, address of this routine is */
740 /* defined in the acp_if network interface struct */
741 /* Calls to: printf() */
742 /* mfreem() */
743 /* splimp() */
744 /* IF_QFULL() */
745 /* IF_DROP() */
746 /* splx() */
747 /* IF_ENQUEUE() */
748 /* m_freem() */
749 /* acp_start() */
750 /* */
751 /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
752
753 acpoutput(ifp, m0, dst)
754 struct ifnet *ifp; /* network interface */
755 struct mbuf *m0; /* buffer */
756 struct sockaddr_in *dst; /* socket destination address */
757 {
758 register struct mbuf *m = m0;
759 register struct acp_softc *ds = &acp_softc[ifp->if_unit];
760 register struct acp_cb *dc;
761 register struct ifqueue *oq;
762 struct mbuf *prev;
763 int s;
764
765 if ((ds->acp_if.if_flags & IFF_UP) == 0)
766 return (ENETDOWN);
767
768 switch (dst->sin_family)
769 {
770
771 #ifdef INET
772 case AF_INET: /* address format of protocol family */
773 /* this is the internet: TCP, UDP, */
774 /* ICMP, IP, etc. */
775 break;
776 #endif INET
777
778 default:
779 printf("acp%d: can't handle af%d\n", ifp->if_unit,
780 dst->sin_family);
781 m_freem(m0);
782 return (EAFNOSUPPORT);
783 }
784
785
786 #ifdef ACPDEBUG
787 if (acp_debug > 6)
788 {
789 printf("acpoutput(): dst = ");
790 prt_addr(dst->sin_addr);
791 printf("\n");
792 }
793 #endif ACPDEBUG
794
795 /* In 4.3, the IP code may pass mbuf chains with 0-length mbufs */
796 /* This causes "transfer count = 0" messages and might even */
797 /* cause actual garbage data transmission if the mbuf is at the */
798 /* end of the chain (we don't think it ever will be, but one */
799 /* can't be too sure...so we scan the chain first). */
800 /* WE DO ASSUME that there is at least one nonempty mbuf! */
801
802 while (m0->m_len == 0)
803 {
804 m = m0;
805 m0 = m0->m_next;
806 m->m_next = 0;
807 m_freem (m);
808 }
809 /* Now we know the first mbuf (at m0) is not zero length */
810 prev = m0;
811 m = m0->m_next;
812 while (m)
813 {
814 if (m->m_len == 0)
815 {
816 prev->m_next = m->m_next;
817 m->m_next = 0;
818 m_freem (m);
819 m = prev->m_next;
820 }
821 else
822 {
823 prev = m;
824 m = m->m_next;
825 }
826 }
827 m = m0; /* reset m to beginning of modified chain */
828
829 s = splimp(); /* disable interrupts */
830
831 dc = &(ds->acp_cb[ACP_DATA]); /* data channel */
832 oq = &(dc->dc_oq); /* point to output queue */
833 if (IF_QFULL(oq)) /* if q full */
834 {
835 IF_DROP(oq); /* drop the data */
836 m_freem(m);
837 ds->acp_if.if_collisions++;
838 splx(s);
839 return (ENOBUFS);
840 }
841 IF_ENQUEUE(oq, m); /* otherwise queue it */
842 acp_start(ds, dc); /* and try to output */
843 splx(s); /* enable interrupts */
844 return (0); /* successful return */
845 }
846
847 /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
848 /*%% ACPIOCTL() %%*/
849 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
850 /* */
851 /* Purpose: */
852 /* */
853 /* This routine processes device dependent ioctl's. Supported */
854 /* ioctls set the host's internet address for this network */
855 /* interface, or send CIMs (Command Interface Messages) to the */
856 /* ACP (ie to bring up the line). The logic for setting the */
857 /* interface address must remain compatible with both ifconfig */
858 /* and acpconfig programs. */
859 /* */
860 /* Call: acpioctl(ifp, cmd, data) */
861 /* Argument: ifp: pointer to the network interface data */
862 /* structure, ifnet */
863 /* cmd: identifies the type of ioctl */
864 /* data: information for the ioctl */
865 /* Returns: 0 for success, or the nonzero error value: */
866 /* EINVAL invalid ioctl request */
867 /* Called by: network software, address of this routine is */
868 /* defined in af_inet network interface struct */
869 /* Calls to: splimp() */
870 /* if_rtinit() */
871 /* in_netof() */
872 /* in_lnaof() */
873 /* acpinit() */
874 /* acpreset() */
875 /* printf() */
876 /* splx() */
877 /* */
878 /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
879
acpioctl(ifp,cmd,data)880 acpioctl(ifp, cmd, data)
881 register struct ifnet *ifp; /* network interface data structure */
882 int cmd; /* type of ioctl request */
883 caddr_t data; /* address of data for ioctl request */
884 {
885 register struct uba_device *ui = acpinfo[ifp->if_unit];
886 struct ifreq *ifr = (struct ifreq *)data; /* ifreq is the interface */
887 /* request struct used for socket ioctls */
888 struct acp_softc *ds = &acp_softc[ifp->if_unit];
889 int s = splimp(), error = 0; /* disable interrupts */
890 #ifdef FOURTWO
891 struct sockaddr_in *sin = (struct sockaddr_in *)&ifr->ifr_addr;
892 #else
893 struct ifaddr *ifa = ds->acp_if.if_addrlist;
894 #endif
895
896 #ifdef ACPDEBUG
897 if (acp_debug > 2)
898 {
899 printf("acp%d: acpioctl()\n", ifp->if_unit);
900 }
901 #endif ACPDEBUG
902
903 switch (cmd)
904 {
905 case SIOCSIFADDR: /* set ifnet address */
906 #ifdef FOURTWO
907 if (ifp->if_flags & IFF_RUNNING)
908 if_rtinit(ifp, -1); /* delete previous route */
909 ifp->if_addr = *(struct sockaddr *)sin;
910 ifp->if_net = in_netof(sin->sin_addr);
911 ifp->if_host[0] = in_lnaof(sin->sin_addr);
912 if (ifp->if_flags & IFF_RUNNING)
913 if_rtinit(ifp, RTF_UP); /* RTF_UP means route useable */
914 else
915 acpinit(ifp->if_unit);
916 #else
917 if (ifa->ifa_addr.sa_family != AF_INET)
918 return(EINVAL);
919 if ((ifp->if_flags & IFF_RUNNING) == 0)
920 acpinit(ifp->if_unit);
921 ds->acp_ipaddr = IA_SIN(ifa)->sin_addr;
922 #endif
923 break;
924
925 case SIOCACPCONFIG:
926 /* if not trying to bring down link (case '0') then trying to bring */
927 /* it up, or reconfigure it -- don't do cmd unless internet address */
928 /* has already been set */
929
930 if (*(ifr->ifr_data) != '0' )
931 {
932 #ifdef FOURTWO
933 sin = (struct sockaddr_in *)&ds->acp_if.if_addr;
934 if (in_netof(sin->sin_addr) == 0)
935 #else
936 if (ds->acp_if.if_addrlist == 0)
937 #endif
938 {
939 printf("acp%d: no internet address is set,", ifp->if_unit);
940 printf(" acpconfig command ignored\n");
941 goto exit;
942 }
943 }
944 acpreset(ifp->if_unit, ui->ui_ubanum); /* reset device */
945 ds->acp_path |= INIT_OK; /* set flag for acpinit() */
946
947 /* if command is set the baud rate, then set clocking for */
948 /* internal generation, and look up the value for the baud */
949 /* rate divisor in the baud_rate table, put this value in */
950 /* the Set System Parameters message, ssp_msg */
951
952 if ( (*(ifr->ifr_data) >= 1) && (*(ifr->ifr_data) <= 14) )
953 {
954 register struct baud *p;
955
956 ssp_msg[CLOCK_OFFSET] = INTERNAL_CLOCK;
957
958 for (p = baud_rate; p->b_value; p++)
959 {
960 if ((*(ifr->ifr_data) - p->b_value) == 0)
961 break;
962 }
963 ssp_msg[BAUD_OFFSET] = p->parameter1;
964 ssp_msg[BAUD_OFFSET + 1] = p->parameter2;
965 if (p->b_value == 0)
966 {
967 printf("acp%d: invalid value for baud rate\n", ifp->if_unit);
968 goto exit;
969 }
970 }
971 else
972 {
973 switch (*(ifr->ifr_data))
974 {
975 case '0':
976 ssp_msg[DOWN_OFFSET] = LINK_DISABLE;
977 break;
978 case '1':
979 ssp_msg[LOOP_OFFSET] = LOOP_NONE;
980 ssp_msg[DTE_OFFSET] = DTE_MODE;
981 ssp_msg[DOWN_OFFSET] = LINK_ENABLE;
982 break;
983 case '2':
984 ssp_msg[LOOP_OFFSET] = LOOP_NONE;
985 ssp_msg[DTE_OFFSET] = DCE_MODE;
986 ssp_msg[DOWN_OFFSET] = LINK_ENABLE;
987 break;
988 case '3':
989 ssp_msg[LOOP_OFFSET] = LOOP_EXTERNAL;
990 ssp_msg[DOWN_OFFSET] = LINK_ENABLE;
991 break;
992 case '4':
993 ssp_msg[LOOP_OFFSET] = LOOP_INTERNAL;
994 ssp_msg[DOWN_OFFSET] = LINK_ENABLE;
995 break;
996 case 'b':
997 ssp_msg[CLOCK_OFFSET] = EXTERNAL_CLOCK;
998 break;
999 default:
1000 error = EINVAL;
1001 goto exit;
1002 }
1003 }
1004 acpinit(ifp->if_unit); /* send ssp_msg to frontend */
1005 break;
1006
1007 default:
1008 error = EINVAL;
1009 }
1010
1011 exit:
1012 splx(s); /* enable interrupts */
1013 return (error);
1014 }
1015
1016 /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1017 /*%% ACPINTA() %%*/
1018 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1019 /* */
1020 /* Purpose: */
1021 /* */
1022 /* This is the interrupt handler for I/O interrupts from the ACP */
1023 /* The I/O mailboxes are scanned for handshake events to process. */
1024 /* The events are Transfer Request, I/O Request done and I/O */
1025 /* Completion ready. Note that the Transfer Request is not yet */
1026 /* supported; an error message is printed if one is received. */
1027 /* */
1028 /* Call: acpinta(unit) */
1029 /* Argument: unit: ACP device unit number */
1030 /* Returns: nothing */
1031 /* Called by: network software, address of this routine is */
1032 /* defined in af_inet network interface struct */
1033 /* Calls to: printf() */
1034 /* start_chn() */
1035 /* acp_data() */
1036 /* acp_supr() */
1037 /* */
1038 /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1039
acpinta(unit)1040 acpinta(unit)
1041 int unit;
1042 {
1043 register struct acpregs *addr = (struct acpregs *)acpinfo[unit]->ui_addr;
1044 register struct acp_softc *ds = &acp_softc[unit];
1045 register struct hdx_chan *hc;
1046 int chan, cc, cnt;
1047
1048 #ifdef ACPDEBUG
1049 if (acp_debug > 7)
1050 {
1051 printf("acp%d: acpinta()\n", unit);
1052 }
1053 #endif ACPDEBUG
1054
1055 /* Figure out what kind of interrupt it was */
1056
1057 if (addr->xfr_flags & FLAGS_RDY) /* Transfer Request Mailbox */
1058 {
1059 printf("acp%d: UNEXPECTED TRANSFER REQUEST!\n", unit);
1060 addr->xfr_cnt = 0;
1061 addr->xfr_flags = (addr->xfr_flags & ~FLAGS_RDY) | FLAGS_DON;
1062 addr->csr |= CSR_INTRA;
1063 }
1064
1065 if (addr->req_flags & FLAGS_DON) /* I/O Request Mailbox */
1066 {
1067 /* try to start any queued i/o request */
1068
1069 if (ds->acp_sioq.sq_head = ds->acp_sioq.sq_head->hc_next)
1070 {
1071 start_chn(ds);
1072 }
1073 else
1074 {
1075 addr->req_flags &= ~FLAGS_DON;
1076 }
1077 }
1078
1079 if (addr->cmp_flags & FLAGS_RDY) /* I/O Completion Mailbox */
1080 {
1081
1082 /*
1083 * Get logical channel info.
1084 */
1085 if ((chan = addr->cmp_chan) > NACPCH)
1086 {
1087 printf("acp%d: unknown channel, chan=%d\n", unit, chan);
1088 return;
1089 }
1090
1091 if (addr->cmp_flags & FLAGS_DIR)
1092 hc = &(ds->acp_cb[chan].dc_wchan);
1093 else
1094 hc = &(ds->acp_cb[chan].dc_rchan);
1095 cc = addr->cmp_stat; /* Mailbox I/O completion status */
1096 cnt = addr->cmp_cnt; /* Mailbox I/O completion byte count */
1097
1098 switch (cc) /* check for unsuccessful I/O completion status */
1099 {
1100 case ACPIOCABT:
1101 printf("acp%d: I/O abort ", unit);
1102 goto daterr;
1103
1104 case ACPIOCERR:
1105 printf("acp%d: program error ", unit);
1106 goto daterr;
1107
1108 case ACPIOCOVR:
1109 printf("acp%d: overrun error ", unit);
1110 goto daterr;
1111
1112 case ACPIOCUBE:
1113 printf("acp%d: NXM timeout or UB parity error ", unit);
1114
1115 daterr:
1116 printf("chan=%d func=%x\n", chan, hc->hc_func);
1117 if (addr->cmp_flags & FLAGS_DIR)
1118 ds->acp_if.if_oerrors++;
1119 else
1120 ds->acp_if.if_ierrors++;
1121 }
1122
1123 /* was it supervisor or data traffic? */
1124
1125 if (chan > ACP_SUPR)
1126 acp_data(ds, hc, cc, cnt);
1127 else
1128 acp_supr(ds, hc, cc, cnt, chan); /* chan = ACP_ALLOC or ACP_SUPR */
1129
1130 /*
1131 * Ack the interrupt. Fix the Mailbox Ready and Done bits: set
1132 * DON bits, and clear RDY bits so mailbox may be reused.
1133 */
1134 addr->cmp_flags = (addr->cmp_flags & ~FLAGS_RDY) | FLAGS_DON;
1135 addr->csr |= CSR_INTRA; /* enable interrupt "a" */
1136
1137 }
1138 }
1139
1140 /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1141 /*%% ACPINTB() %%*/
1142 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1143 /* */
1144 /* Purpose: */
1145 /* */
1146 /* This is the interrupt handler for system interrupts from the */
1147 /* ACP. */
1148 /* */
1149 /* Call: acpintb(unit) */
1150 /* Argument: unit: ACP device unit number */
1151 /* Returns: nothing */
1152 /* Called by: network software, address of this routine is */
1153 /* defined in af_inet network interface struct */
1154 /* Calls to: printf() */
1155 /* acpinit() */
1156 /* */
1157 /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1158
acpintb(unit)1159 acpintb(unit)
1160 int unit;
1161 {
1162 register struct acpregs *addr = (struct acpregs *)acpinfo[unit]->ui_addr;
1163 register struct acp_softc *ds = &acp_softc[unit];
1164
1165 #ifdef ACPDEBUG
1166 if (acp_debug > 1)
1167 {
1168 printf("acp%d: acpintb()\n", unit);
1169 }
1170 #endif ACPDEBUG
1171
1172 if (ds->acp_flags & ACPF_OK)
1173 {
1174 printf("acp%d: Unexpected System interrupt, status = %d\n",
1175 unit, addr->sys_stat);
1176 addr->csr = 0;
1177 printf("acp%d: DISABLED!\n", unit);
1178 ds->acp_if.if_flags &= ~(IFF_RUNNING | IFF_UP);
1179 }
1180 else
1181 {
1182 if (addr->sys_stat != ACPSTAT_OK)
1183 {
1184 printf("acp%d: PWRUP Diagnostic failure = %d\n",
1185 unit, addr->sys_stat);
1186 addr->csr = 0;
1187 }
1188 else
1189 {
1190 ds->acp_flags |= ACPF_OK;
1191 addr->csr |= (CSR_IENA | CSR_DMAEN);
1192 acpinit(unit);
1193 }
1194 }
1195 }
1196
1197 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1198 /*%% %%*/
1199 /*%% LOCAL ROUTINES %%*/
1200 /*%% %%*/
1201 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1202
1203 /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1204 /*%% ACP_ALLOC() %%*/
1205 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1206 /* */
1207 /* Purpose: */
1208 /* */
1209 /* This routine allocates control or data paths. Commands are */
1210 /* sent (over DPN 0) from the host to the ALLOC facility on the */
1211 /* front end to allocate the paths. The ALLOC facility returns */
1212 /* a response to the allocation command which indicates success */
1213 /* or failure. Note that DPN 0 is used only for the ALLOC */
1214 /* commands, and is not a control path as it was been in the */
1215 /* past. The paths are symbolically defined as ACP_ALLOC, */
1216 /* ACP_SUPR, and ACP_DATA for allocation messages, control */
1217 /* messages, and data respectively. The CID field indicates */
1218 /* the data path number of the allocation command. The CID */
1219 /* is set here so that the response will have the same CID, and */
1220 /* will therefore indicate to which path the response */
1221 /* corresponds. (The CID is set in the command and must be */
1222 /* returned, untouched, in the response.) */
1223 /* */
1224 /* Call: acp_alloc(ds, type) */
1225 /* Argument: ds: pointer to ACP device control structure */
1226 /* type: specifies if path is for control or data */
1227 /* Returns: nothing */
1228 /* Called by: acpinit() */
1229 /* Calls to: MGET() */
1230 /* printf() */
1231 /* mtod() */
1232 /* bcopy() */
1233 /* sizeof() */
1234 /* IF_ENQUEUE() */
1235 /* acp_start() */
1236 /* */
1237 /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1238
acp_alloc(ds,type)1239 static void acp_alloc(ds, type)
1240 struct acp_softc *ds;
1241 int type;
1242 {
1243 struct mbuf *m;
1244 register u_char *bp;
1245
1246 #ifdef ACPDEBUG
1247 if (acp_debug > 4)
1248 {
1249 printf("acp%d: acp_alloc()\n", ds->acp_if.if_unit);
1250 }
1251 #endif ACPDEBUG
1252
1253 MGET(m, M_DONTWAIT, MT_DATA); /* try to get init buffer */
1254 if (m == 0)
1255 {
1256 printf("acp%d: couldn't get init buffer\n", ds->acp_if.if_unit);
1257 return;
1258 }
1259
1260 /* modify the path allocation message to get a control path */
1261 /* or a data path */
1262
1263 if (type == TYPE_CNTL)
1264 {
1265 alloc_msg[CID_OFFSET] = ACP_SUPR; /* set CID for response */
1266 alloc_msg[DPN_OFFSET] = ACP_SUPR; /* path number */
1267 alloc_msg[TYPE_OFFSET] = TYPE_CNTL; /* path type = control */
1268 }
1269 else
1270 {
1271 alloc_msg[CID_OFFSET] = ACP_DATA; /* set CID for response */
1272 alloc_msg[DPN_OFFSET] = ACP_DATA; /* path number */
1273 alloc_msg[TYPE_OFFSET] = TYPE_DATA; /* path type = data */
1274 }
1275
1276 bp = mtod(m, u_char *); /* point to data section of mbuf */
1277
1278 bcopy(alloc_msg, bp, sizeof(alloc_msg)); /* set sys params msg in mbuf */
1279
1280 #ifdef ACPDEBUG
1281 if (acp_debug > 5)
1282 {
1283 printf("acp_alloc(): ");
1284 prt_bytes(bp, sizeof(alloc_msg)); /* print 12-byte header + data */
1285 printf("\n");
1286 }
1287 #endif ACPDEBUG
1288
1289
1290 m->m_len = sizeof(alloc_msg); /* set msg length */
1291
1292 IF_ENQUEUE(&(ds->acp_cb[ACP_ALLOC].dc_oq), m); /* output queue */
1293
1294 acp_start(ds, &(ds->acp_cb[ACP_ALLOC])); /* start ouput of data */
1295 }
1296
1297
1298 /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1299 /*%% ACP_INIT() %%*/
1300 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1301 /* */
1302 /* Purpose: */
1303 /* */
1304 /* This routine builds and sends an initialization message to */
1305 /* the ACP. A canned Set System Parameters Message is sent to */
1306 /* start HDLC. */
1307 /* */
1308 /* Call: acp_init(ds) */
1309 /* Argument: ds: pointer to ACP device control structure */
1310 /* Returns: nothing */
1311 /* Called by: acpinit() */
1312 /* Calls to: MGET() */
1313 /* printf() */
1314 /* mtod() */
1315 /* bcopy() */
1316 /* sizeof() */
1317 /* IF_ENQUEUE() */
1318 /* acp_start() */
1319 /* */
1320 /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1321
acp_init(ds)1322 static void acp_init(ds)
1323 struct acp_softc *ds;
1324 {
1325 struct mbuf *m;
1326 register u_char *bp;
1327
1328 #ifdef ACPDEBUG
1329 if (acp_debug > 5)
1330 {
1331 printf("acp%d: acp_init()\n", ds->acp_if.if_unit);
1332 }
1333 #endif ACPDEBUG
1334
1335 MGET(m, M_DONTWAIT, MT_DATA); /* try to get init buffer */
1336 if (m == 0)
1337 {
1338 printf("acp%d: couldn't get init buffer\n", ds->acp_if.if_unit);
1339 return;
1340 }
1341
1342 bp = mtod(m, u_char *); /* point to data section of mbuf */
1343
1344 bcopy(ssp_msg, bp, sizeof(ssp_msg)); /* put msg into mbuf */
1345
1346 #ifdef ACPDEBUG
1347 if (acp_debug > 4)
1348 {
1349 printf("acp_init(): ssp msg\n");
1350 prt_bytes(bp, sizeof(ssp_msg)); /* print 12-byte header + data */
1351 printf("\n");
1352 }
1353 #endif ACPDEBUG
1354
1355 m->m_len = sizeof(ssp_msg); /* set msg length */
1356
1357 IF_ENQUEUE(&(ds->acp_cb[ACP_SUPR].dc_oq), m); /* output queue */
1358
1359 acp_start(ds, &(ds->acp_cb[ACP_SUPR])); /* start ouput of data */
1360 }
1361
1362 /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1363 /*%% ACP_START() %%*/
1364 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1365 /* */
1366 /* Purpose: */
1367 /* */
1368 /* This routine attempts to start output of data queued on a */
1369 /* specific LCN. If the LCN was not already busy and data is */
1370 /* available for output, the data is copied into the LCN's I/O */
1371 /* buffer and an I/O request queued to the ACP. */
1372 /* */
1373 /* Call: acpstart(ds, dc) */
1374 /* Arguments: ds: pointer to device control structure */
1375 /* dc: pointer to the Logical Channel control */
1376 /* block structure */
1377 /* Returns: nothing */
1378 /* Called by: acpoutput() */
1379 /* acp_init() */
1380 /* acp_data() */
1381 /* acp_supr() */
1382 /* Calls to: IF_DEQUEUE() */
1383 /* if_wubaput() */
1384 /* acp_ioreqs() */
1385 /* */
1386 /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1387
acp_start(ds,dc)1388 static void acp_start(ds, dc)
1389 register struct acp_softc *ds;
1390 register struct acp_cb *dc;
1391 {
1392 register struct mbuf *m;
1393 int len;
1394
1395 /*
1396 * If output isn't active, attempt to
1397 * start sending a new packet.
1398 */
1399
1400 #ifdef ACPDEBUG
1401 if (acp_debug > 7)
1402 {
1403 printf("acp: acp_start()\n");
1404 }
1405 #endif ACPDEBUG
1406
1407 if ((dc->dc_flags & DC_OBUSY) || (dc->dc_oq.ifq_len == 0))
1408 return;
1409
1410 IF_DEQUEUE(&dc->dc_oq, m); /* remove data from LCN output queue */
1411
1412 len = if_wubaput(&dc->dc_ifuba, m); /* copy data to mapped mem */
1413
1414 if (len > ds->acp_maxout)
1415 {
1416
1417 #ifdef ACPDEBUG
1418 if (acp_debug > 7)
1419 {
1420 printf("acp: %d byte msg sent.\n", len);
1421 }
1422 #endif ACPDEBUG
1423
1424 ds->acp_maxout = len;
1425 }
1426
1427 dc->dc_flags |= DC_OBUSY;
1428
1429 acp_iorq(ds, dc, len, ACPWRT+ACPEOS); /* build I/O request, enqueue */
1430 }
1431
1432 /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1433 /*%% ACP_IORQ() %%*/
1434 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1435 /* */
1436 /* Purpose: */
1437 /* */
1438 /* This routine builds ACP I/O requests and queues them for */
1439 /* delivery to the ACP. If the ACP I/O request comm regs are */
1440 /* not busy, the I/O request is passed to the ACP. */
1441 /* */
1442 /* Call: acp_iorq(ds, dc, len, func) */
1443 /* Argument: ds: pointer to device control block struct */
1444 /* dc: pointer to the Logical Channel control */
1445 /* block structure */
1446 /* len: byte count */
1447 /* func: the function: read or write */
1448 /* Returns: nothing */
1449 /* Called by: acpinit() */
1450 /* acp_start() */
1451 /* acp_data() */
1452 /* acp_supr() */
1453 /* Calls to: start_chn() */
1454 /* */
1455 /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1456
acp_iorq(ds,dc,len,func)1457 static void acp_iorq(ds, dc, len, func)
1458 struct acp_softc *ds;
1459 struct acp_cb *dc;
1460 int len, func;
1461 {
1462 register struct hdx_chan *hc;
1463 register int info;
1464
1465
1466 #ifdef ACPDEBUG
1467 if (acp_debug > 6)
1468 printf("acp: acp_iorq()\n");
1469 #endif ACPDEBUG
1470
1471 /* get appropriate UNIBUS mapping info */
1472
1473 if ((func & FCN_MASK) == ACPRED) /* read or write? */
1474 {
1475 hc = &dc->dc_rchan; /* read */
1476 info = dc->dc_ifuba.ifu_r.ifrw_info;
1477 }
1478 else
1479 {
1480 hc = &dc->dc_wchan; /* write */
1481 info = dc->dc_ifuba.ifu_w.ifrw_info;
1482 }
1483
1484 /* set channel info */
1485
1486 hc->hc_adx = (u_char)((info & 0x30000) >> 12); /* address bits 17-16 */
1487 hc->hc_addr = (unsigned short)(info & 0xffff); /* address bits 15-00 */
1488 hc->hc_cnt = len; /* byte count */
1489 hc->hc_func = (u_char)func; /* I/O function */
1490
1491 if (dc->dc_lcn > ACP_SUPR)
1492 hc->hc_sbfc = SBFCN_DATA; /* I/O subfunction for data */
1493 else
1494 hc->hc_sbfc = SBFCN_SUPR; /* I/O subfunction for cntrl */
1495
1496 /*
1497 * If ACP comm regs busy, queue start i/o for later.
1498 */
1499 if (ds->acp_sioq.sq_head)
1500 {
1501 (ds->acp_sioq.sq_tail)->hc_next = hc;
1502 ds->acp_sioq.sq_tail = hc;
1503 hc->hc_next = 0;
1504 return;
1505 }
1506
1507 /* start i/o on channel now */
1508
1509 ds->acp_sioq.sq_head = hc;
1510 ds->acp_sioq.sq_tail = hc;
1511 hc->hc_next = 0;
1512 start_chn(ds);
1513 }
1514
1515 /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1516 /*%% START_CHN() %%*/
1517 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1518 /* */
1519 /* Purpose: */
1520 /* */
1521 /* This routine copies ACP I/O requests into the ACP comm regs */
1522 /* and notifies the ACP. */
1523 /* */
1524 /* Call: start_chn(ds) */
1525 /* Argument: ds: pointer to device control block struct */
1526 /* Returns: nothing */
1527 /* Called by: acpinta() */
1528 /* acp_iorq() */
1529 /* Calls to: none */
1530 /* */
1531 /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1532
start_chn(ds)1533 static void start_chn(ds)
1534 struct acp_softc *ds;
1535 {
1536 register struct hdx_chan *hc = ds->acp_sioq.sq_head;
1537 register struct acpregs *addr =
1538 (struct acpregs *)acpinfo[ds->acp_if.if_unit]->ui_addr;
1539
1540 /*
1541 * Set up comm regs.
1542 */
1543
1544 #ifdef ACPDEBUG
1545 if (acp_debug > 7)
1546 {
1547 printf("acp: start_chn()\n");
1548 }
1549 #endif ACPDEBUG
1550
1551 addr->req_chan = hc->hc_chan >> 1;
1552 addr->req_adx = hc->hc_adx;
1553 addr->req_addr = hc->hc_addr;
1554 addr->req_cnt = hc->hc_cnt;
1555 addr->req_fcn = hc->hc_func;
1556 addr->req_sbf = hc->hc_sbfc;
1557 if (hc->hc_chan & 1)
1558 addr->req_flags = FLAGS_RDY | FLAGS_DIR;
1559 else
1560 addr->req_flags = FLAGS_RDY;
1561
1562 addr->csr |= CSR_INTRA;
1563 }
1564
1565 /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1566 /*%% ACP_DATA() %%*/
1567 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1568 /* */
1569 /* Purpose: */
1570 /* */
1571 /* This routine is called when a data channel I/O completes. */
1572 /* If the completion was for a write, an attempt is made to */
1573 /* start output on the next packet waiting for output on that */
1574 /* LCN. If the completion was for a read, the received packet */
1575 /* is sent to the IP input queue (if no error) and another read */
1576 /* is started on the LCN. */
1577 /* */
1578 /* Call: acp_data(ds, hc, cc, rcnt) */
1579 /* Arguments: ds: pointer to device control block struct */
1580 /* hc: pointer to half duplex channel control */
1581 /* block */
1582 /* cc: Mailbox I/O completion status */
1583 /* rcnt: byte count */
1584 /* Returns: nothing */
1585 /* Called by: acpinta() */
1586 /* Calls to: m_freem() */
1587 /* acp_start() */
1588 /* if_rubaget() */
1589 /* IF_QFULL() */
1590 /* IF_DROP() */
1591 /* IF_ENQUEUE() */
1592 /* schednetisr() */
1593 /* acp_ioreq() */
1594 /* */
1595 /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1596
acp_data(ds,hc,cc,rcnt)1597 static void acp_data(ds, hc, cc, rcnt)
1598 register struct acp_softc *ds;
1599 register struct hdx_chan *hc;
1600 int cc, rcnt;
1601 {
1602 register struct acp_cb *dc = &(ds->acp_cb[hc->hc_chan/2]);
1603 register struct ifqueue *inq = &ipintrq;
1604 register struct mbuf *m;
1605
1606 if (hc->hc_chan & 0x01) /* was it read or write? */
1607 { /* write, fire up next output */
1608 ds->acp_if.if_opackets++;
1609 if (dc->dc_ifuba.ifu_xtofree)
1610 {
1611 m_freem(dc->dc_ifuba.ifu_xtofree);
1612 dc->dc_ifuba.ifu_xtofree = 0;
1613 }
1614 dc->dc_flags &= ~DC_OBUSY;
1615 acp_start(ds, dc);
1616 }
1617 else /* read, process rcvd packet */
1618 {
1619
1620 #ifdef ACPDEBUG
1621 if (acp_debug > 6)
1622 {
1623 printf("acp: data read completed, cc = %d, cnt = %d\n", cc, rcnt);
1624 prt_bytes((u_char *)(dc->dc_ifuba.ifu_r.ifrw_addr), (rcnt < 20 ? rcnt:20));
1625 }
1626 #endif ACPDEBUG
1627
1628 if (cc == ACPIOCOK)
1629 { /* Queue good packet for input */
1630 ds->acp_if.if_ipackets++;
1631 if (rcnt > ds->acp_maxin)
1632 {
1633
1634 #ifdef ACPDEBUG
1635 if (acp_debug > 4)
1636 {
1637 printf("acp: %d byte msg received.\n", rcnt);
1638 }
1639 #endif ACPDEBUG
1640
1641 ds->acp_maxin = rcnt;
1642 }
1643 /* call if_rubaget() to pull read data */
1644 /* off the interface, the args are the */
1645 /* ifuba struct, the length of data, */
1646 /* and the 0 indicates that no trailer */
1647 /* protocol is used */
1648 m = if_rubaget(&(dc->dc_ifuba), rcnt, 0, &(ds->acp_if));
1649 if (m)
1650 {
1651 if (IF_QFULL(inq))
1652 {
1653 IF_DROP(inq);
1654 m_freem(m);
1655 }
1656 else
1657 {
1658 IF_ENQUEUE(inq, m);
1659 schednetisr(NETISR_IP);
1660 }
1661 }
1662 }
1663
1664 /* hang a new data read */
1665
1666 acp_iorq(ds, dc, ACPMTU, ACPRED+ACPSTR);
1667
1668 }
1669 }
1670
1671 /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1672 /*%% ACP_RESPONSE() %%*/
1673 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1674 /* */
1675 /* Purpose: */
1676 /* */
1677 /* This routine sends a Control Interface Message (CIM) response */
1678 /* to the front end to indicate that a CIM command from the */
1679 /* front end was successfully received. Presently there are two */
1680 /* types of CIM responses sent to the front end: frame level */
1681 /* up, and frame level down. Future applications may send a */
1682 /* CIM response to DCP CIM commands. The basic philosophy with */
1683 /* CIMs is that there is always a paired command/response which */
1684 /* is exchanged between the host and the front end. */
1685 /* Currently, the front end does not process the responses from */
1686 /* the host, they are merely discarded. The one thing left to */
1687 /* do in the case that the front end does ever look at these */
1688 /* responses is to use the same CID (Command ID field, bytes 5 */
1689 /* to 8 of the CIM header) that was present in the command. */
1690 /* */
1691 /* Call: acp_response(ds, response) */
1692 /* Argument: ds: pointer to ACP device control structure */
1693 /* response: response for CIM command field */
1694 /* the response value = command value + 1 */
1695 /* Returns: nothing */
1696 /* Called by: supr_msg() */
1697 /* Calls to: MGET() */
1698 /* printf() */
1699 /* mtod() */
1700 /* bcopy() */
1701 /* sizeof() */
1702 /* IF_ENQUEUE() */
1703 /* acp_start() */
1704 /* */
1705 /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1706
acp_response(ds,response)1707 static void acp_response(ds, response)
1708 struct acp_softc *ds;
1709 u_char response;
1710 {
1711 struct mbuf *m;
1712 u_char *bp;
1713
1714 MGET(m, M_DONTWAIT, MT_DATA); /* try to get init buffer */
1715 if (m == 0)
1716 {
1717 printf("acp%d: couldn't get init buffer\n", ds->acp_if.if_unit);
1718 return;
1719 }
1720 /* put response in CIM cmd field */
1721
1722 response_msg[CMD_OFFSET] = response;
1723
1724 bp = mtod(m, u_char *); /* point to data section of mbuf */
1725
1726 bcopy(response_msg, bp, sizeof(response_msg)); /* put msg in mbuf */
1727
1728 #ifdef ACPDEBUG
1729 if (acp_debug > 6)
1730 {
1731 printf("acp_response(): ");
1732 prt_bytes(bp, sizeof(response_msg)); /* print messge */
1733 printf("\n");
1734 }
1735 #endif ACPDEBUG
1736
1737 m->m_len = sizeof(response_msg); /* set msg length */
1738
1739 IF_ENQUEUE(&(ds->acp_cb[ACP_SUPR].dc_oq), m); /* output queue */
1740
1741 acp_start(ds, &(ds->acp_cb[ACP_SUPR])); /* start ouput of data */
1742 }
1743
1744 /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1745 /*%% ACP_SUPR() %%*/
1746 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1747 /* */
1748 /* Purpose: */
1749 /* */
1750 /* This routine is called when a supervisor I/O completes. */
1751 /* If the completion was for a write, an attempt is made to */
1752 /* start output on the next supervisor command waiting for */
1753 /* output. If the completion was for a read, the received */
1754 /* supervisor message is processed and another read is started. */
1755 /* */
1756 /* Call: acp_supr(ds, hc, cc, rcnt, channel) */
1757 /* Argument: ds: pointer to dev control block struct */
1758 /* hc: pointer to the Half Duplex cntrl */
1759 /* block structure */
1760 /* cc: Mailbox I/O completion status */
1761 /* rcnt: byte count, length of data */
1762 /* channel: indicates ACP_ALLOC or ACP_SUPR */
1763 /* Returns: nothing */
1764 /* Called by: acpinta() */
1765 /* Calls to: m_freem() */
1766 /* acp_start() */
1767 /* supr_msg() */
1768 /* acp_ioreq() */
1769 /* */
1770 /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1771
acp_supr(ds,hc,cc,rcnt,chan)1772 static void acp_supr(ds, hc, cc, rcnt, chan)
1773 register struct acp_softc *ds;
1774 register struct hdx_chan *hc;
1775 int cc, rcnt, chan;
1776 {
1777 register struct acp_cb *dc = &(ds->acp_cb[chan]);
1778 register u_char *p;
1779
1780 /* was it read or write? */
1781
1782 if (hc->hc_chan & 0x01)
1783 {
1784 if (dc->dc_ifuba.ifu_xtofree)
1785 {
1786 m_freem(dc->dc_ifuba.ifu_xtofree);
1787 dc->dc_ifuba.ifu_xtofree = 0;
1788 }
1789 dc->dc_flags &= ~DC_OBUSY;
1790 acp_start(ds, dc);
1791 }
1792 else
1793 {
1794
1795 #ifdef ACPDEBUG
1796 if (acp_debug > 3)
1797 {
1798 printf("acp: acp_supr(), read completed, cc = %d, cnt = %d\n", cc, rcnt);
1799 prt_bytes((u_char *)(dc->dc_ifuba.ifu_r.ifrw_addr), rcnt);
1800 printf("\n");
1801 }
1802 #endif ACPDEBUG
1803
1804 if (cc == ACPIOCOK)
1805 {
1806 p = (u_char *)(dc->dc_ifuba.ifu_r.ifrw_addr);
1807
1808 /* process supervisor message */
1809 supr_msg(ds, p);
1810 }
1811 /* hang a new supr read */
1812 acp_iorq(ds, dc, ACPMTU, ACPRED+ACPSTR);
1813 }
1814 }
1815
1816 /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1817 /*%% SUPR_MSG() %%*/
1818 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1819 /* */
1820 /* Purpose: */
1821 /* */
1822 /* This routine processes received supervisor messages. */
1823 /* Depending on the message type, the appropriate action is */
1824 /* taken. Note that the RSF field is checked for responses. */
1825 /* The RSF field is 4 bytes long, but ony that least */
1826 /* significant byte is used. */
1827 /* */
1828 /* Call: supr_msg(ds, p) */
1829 /* Arguments: ds: pointer to dev control block struct */
1830 /* p: pointer to a character array */
1831 /* containing the supervisor message */
1832 /* Returns: nothing */
1833 /* Called by: acp_supr() */
1834 /* Calls to: printf() */
1835 /* IF_DEQUEUE() */
1836 /* m_freem() */
1837 /* acp_response() */
1838 /* */
1839 /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1840
supr_msg(ds,p)1841 static void supr_msg(ds, p)
1842 struct acp_softc *ds;
1843 u_char p[];
1844 {
1845 register struct acp_cb *dc;
1846 register int lcn;
1847 register struct mbuf *m;
1848
1849 switch (p[3])
1850 {
1851 case RSP_ALLOC: /* alloc response */
1852 if (p[RSF_OFFSET]) /* check if RSF is 0 for success */
1853 {
1854 printf("acp%d: attempt to allocate path failed ");
1855 printf("rsf field = %x\n", p[RSF_OFFSET]);
1856 return;
1857 }
1858 else
1859 {
1860 if (p[CID_OFFSET] >= ACP_SUPR && p[CID_OFFSET] <= ACP_DATA )
1861 ds->acp_path |= p[CID_OFFSET];
1862 else
1863 {
1864 printf("acp%d: path allocation ",ds->acp_if.if_unit);
1865 printf("response contains invalid DPN = %d\n", p[CID_OFFSET]);
1866 }
1867 }
1868 break;
1869
1870 case RSP_DEALLOC: /* dealloc response */
1871 if (p[RSF_OFFSET]) /* check if RSF is 0 for success */
1872 {
1873 printf("acp%d: attempt to deallocate path failed ");
1874 printf("rsf field = %x\n", p[RSF_OFFSET]);
1875 return;
1876 }
1877 break;
1878
1879 case RSP_SSP: /* set sys parm rsp */
1880 if (p[RSF_OFFSET]) /* check if RSF is 0 for success */
1881 {
1882 printf("acp%d: attempt to set HDLC system parameters failed\n");
1883 return;
1884 }
1885 break;
1886
1887 case CMD_FLUP: /* frame level up */
1888
1889 /* check that the data path was successfully allocated, we */
1890 /* know that the control path was successfully allocated */
1891 /* otherwise the FLUP command would not have been issued */
1892
1893 if ((ds->acp_path & ACP_DATA) == 0)
1894 {
1895 printf("acp%d: data path was not successfully allocated\n",
1896 ds->acp_if.if_unit);
1897 }
1898 ds->acp_if.if_flags |= IFF_UP;
1899 printf("acp%d: frame level up\n", ds->acp_if.if_unit);
1900 acp_response(ds, RSP_FLUP); /* send response to front end */
1901 break;
1902
1903 case CMD_FLDWN: /* frame level down */
1904 ds->acp_if.if_flags &= ~IFF_UP;
1905 dc = ds->acp_cb;
1906 for(lcn=ACP_ALLOC;lcn<=NACPCH;lcn++) /* for all LCN's */
1907 {
1908 while (dc->dc_oq.ifq_len) /* drop pending data */
1909 {
1910 IF_DEQUEUE(&dc->dc_oq, m);
1911 m_freem(m);
1912 }
1913 dc++;
1914 }
1915 printf("acp%d: frame level down\n", ds->acp_if.if_unit);
1916 acp_response(ds, RSP_FLDWN); /* send response to front end */
1917 break;
1918
1919 default:
1920 printf("acp%d: supervisor error, code=%x\n",
1921 ds->acp_if.if_unit, p[3]);
1922 }
1923 }
1924
1925
1926 #ifdef ACPDEBUG
1927
1928 /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1929 /*%% PRT_ADDR() %%*/
1930 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1931 /* */
1932 /* Purpose: */
1933 /* */
1934 /* This routine is used to print internet addresses in the */
1935 /* standard A.B.C.D format. Note that this routine is for */
1936 /* debugging purposes (ifdef ACPDEBUG). */
1937 /* */
1938 /* Call: prt_addr(addr) */
1939 /* Argument: addr: internet address structure */
1940 /* Returns: nothing */
1941 /* Called by: acpoutput() */
1942 /* Calls to: printf() */
1943 /* */
1944 /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1945
prt_addr(addr)1946 static void prt_addr(addr)
1947 struct in_addr addr;
1948 {
1949 #ifndef FOURTWO
1950 union {
1951 struct in_addr ip;
1952 struct { /* (assume Class A network number) */
1953 u_char s_net;
1954 u_char s_host;
1955 u_char s_lh;
1956 u_char s_impno;
1957 } imp;
1958 } imp_addr;
1959 imp_addr.ip = addr;
1960 printf("%d.%d.%d.%d", imp_addr.imp.s_net, imp_addr.imp.s_host,
1961 imp_addr.imp.s_lh, imp_addr.imp.s_impno);
1962 #else
1963 printf("%d.%d.%d.%d", addr.s_net, addr.s_host, addr.s_lh, addr.s_impno);
1964 #endif
1965 }
1966
1967 /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1968 /*%% PRT_BYTES() %%*/
1969 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1970 /* */
1971 /* Purpose: */
1972 /* */
1973 /* This routine is used to print a string of bytes in hex. */
1974 /* Note that this routine is for debugging purposes (ifdef */
1975 /* ACPDEBUG). */
1976 /* */
1977 /* Call: prt_bytes(bp, cnt) */
1978 /* Argument: bp: pointer to the string */
1979 /* cnt: number of bytes */
1980 /* Returns: nothing */
1981 /* Called by: acp_data() */
1982 /* acp_supr() */
1983 /* supr_msg() */
1984 /* Calls to: printf() */
1985 /* */
1986 /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1987
prt_bytes(bp,cnt)1988 static void prt_bytes(bp, cnt)
1989 u_char *bp;
1990 int cnt;
1991 {
1992 while(cnt--)
1993 {
1994 printf(" %x", *bp++ & 0xff);
1995 }
1996 }
1997
1998 #endif ACPDEBUG
1999
2000 #endif NACP
2001