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