1 /*- 2 * Copyright (c) 1997-2001 Granch, Ltd. All rights reserved. 3 * Author: Denis I.Timofeev <timofeev@granch.ru> 4 * 5 * Redistributon and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice unmodified, this list of conditions, and the following 10 * disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 * 27 */ 28 29 #include <sys/cdefs.h> 30 __FBSDID("$FreeBSD$"); 31 32 /* 33 * Device driver for Granch SBNI12 leased line adapters 34 * 35 * Revision 2.0.0 1997/08/06 36 * Initial revision by Alexey Zverev 37 * 38 * Revision 2.0.1 1997/08/11 39 * Additional internal statistics support (tx statistics) 40 * 41 * Revision 2.0.2 1997/11/05 42 * if_bpf bug has been fixed 43 * 44 * Revision 2.0.3 1998/12/20 45 * Memory leakage has been eliminated in 46 * the sbni_st and sbni_timeout routines. 47 * 48 * Revision 3.0 2000/08/10 by Yaroslav Polyakov 49 * Support for PCI cards. 4.1 modification. 50 * 51 * Revision 3.1 2000/09/12 52 * Removed extra #defines around bpf functions 53 * 54 * Revision 4.0 2000/11/23 by Denis Timofeev 55 * Completely redesigned the buffer management 56 * 57 * Revision 4.1 2001/01/21 58 * Support for PCI Dual cards and new SBNI12D-10, -11 Dual/ISA cards 59 * 60 * Written with reference to NE2000 driver developed by David Greenman. 61 */ 62 63 64 #include <sys/param.h> 65 #include <sys/systm.h> 66 #include <sys/socket.h> 67 #include <sys/sockio.h> 68 #include <sys/mbuf.h> 69 #include <sys/kernel.h> 70 #include <sys/priv.h> 71 #include <sys/proc.h> 72 #include <sys/callout.h> 73 #include <sys/syslog.h> 74 #include <sys/random.h> 75 76 #include <machine/bus.h> 77 #include <sys/rman.h> 78 #include <machine/resource.h> 79 80 #include <net/if.h> 81 #include <net/if_dl.h> 82 #include <net/ethernet.h> 83 #include <net/bpf.h> 84 #include <net/if_types.h> 85 86 #include <dev/sbni/if_sbnireg.h> 87 #include <dev/sbni/if_sbnivar.h> 88 89 #define ASM_CRC 1 90 91 static void sbni_init(void *); 92 static void sbni_start(struct ifnet *); 93 static int sbni_ioctl(struct ifnet *, u_long, caddr_t); 94 static void sbni_watchdog(struct ifnet *); 95 static void sbni_stop(struct sbni_softc *); 96 static void handle_channel(struct sbni_softc *); 97 98 static void card_start(struct sbni_softc *); 99 static int recv_frame(struct sbni_softc *); 100 static void send_frame(struct sbni_softc *); 101 static int upload_data(struct sbni_softc *, u_int, u_int, u_int, u_int32_t); 102 static int skip_tail(struct sbni_softc *, u_int, u_int32_t); 103 static void interpret_ack(struct sbni_softc *, u_int); 104 static void download_data(struct sbni_softc *, u_int32_t *); 105 static void prepare_to_send(struct sbni_softc *); 106 static void drop_xmit_queue(struct sbni_softc *); 107 static int get_rx_buf(struct sbni_softc *); 108 static void indicate_pkt(struct sbni_softc *); 109 static void change_level(struct sbni_softc *); 110 static int check_fhdr(struct sbni_softc *, u_int *, u_int *, 111 u_int *, u_int *, u_int32_t *); 112 static int append_frame_to_pkt(struct sbni_softc *, u_int, u_int32_t); 113 static void timeout_change_level(struct sbni_softc *); 114 static void send_frame_header(struct sbni_softc *, u_int32_t *); 115 static void set_initial_values(struct sbni_softc *, struct sbni_flags); 116 117 static u_int32_t calc_crc32(u_int32_t, caddr_t, u_int); 118 static timeout_t sbni_timeout; 119 120 static __inline u_char sbni_inb(struct sbni_softc *, enum sbni_reg); 121 static __inline void sbni_outb(struct sbni_softc *, enum sbni_reg, u_char); 122 static __inline void sbni_insb(struct sbni_softc *, u_char *, u_int); 123 static __inline void sbni_outsb(struct sbni_softc *, u_char *, u_int); 124 125 static u_int32_t crc32tab[]; 126 127 #ifdef SBNI_DUAL_COMPOUND 128 struct sbni_softc *sbni_headlist; 129 #endif 130 131 u_int32_t next_sbni_unit; 132 133 /* -------------------------------------------------------------------------- */ 134 135 static __inline u_char 136 sbni_inb(struct sbni_softc *sc, enum sbni_reg reg) 137 { 138 return bus_space_read_1( 139 rman_get_bustag(sc->io_res), 140 rman_get_bushandle(sc->io_res), 141 sc->io_off + reg); 142 } 143 144 static __inline void 145 sbni_outb(struct sbni_softc *sc, enum sbni_reg reg, u_char value) 146 { 147 bus_space_write_1( 148 rman_get_bustag(sc->io_res), 149 rman_get_bushandle(sc->io_res), 150 sc->io_off + reg, value); 151 } 152 153 static __inline void 154 sbni_insb(struct sbni_softc *sc, u_char *to, u_int len) 155 { 156 bus_space_read_multi_1( 157 rman_get_bustag(sc->io_res), 158 rman_get_bushandle(sc->io_res), 159 sc->io_off + DAT, to, len); 160 } 161 162 static __inline void 163 sbni_outsb(struct sbni_softc *sc, u_char *from, u_int len) 164 { 165 bus_space_write_multi_1( 166 rman_get_bustag(sc->io_res), 167 rman_get_bushandle(sc->io_res), 168 sc->io_off + DAT, from, len); 169 } 170 171 172 /* 173 Valid combinations in CSR0 (for probing): 174 175 VALID_DECODER 0000,0011,1011,1010 176 177 ; 0 ; - 178 TR_REQ ; 1 ; + 179 TR_RDY ; 2 ; - 180 TR_RDY TR_REQ ; 3 ; + 181 BU_EMP ; 4 ; + 182 BU_EMP TR_REQ ; 5 ; + 183 BU_EMP TR_RDY ; 6 ; - 184 BU_EMP TR_RDY TR_REQ ; 7 ; + 185 RC_RDY ; 8 ; + 186 RC_RDY TR_REQ ; 9 ; + 187 RC_RDY TR_RDY ; 10 ; - 188 RC_RDY TR_RDY TR_REQ ; 11 ; - 189 RC_RDY BU_EMP ; 12 ; - 190 RC_RDY BU_EMP TR_REQ ; 13 ; - 191 RC_RDY BU_EMP TR_RDY ; 14 ; - 192 RC_RDY BU_EMP TR_RDY TR_REQ ; 15 ; - 193 */ 194 195 #define VALID_DECODER (2 + 8 + 0x10 + 0x20 + 0x80 + 0x100 + 0x200) 196 197 198 int 199 sbni_probe(struct sbni_softc *sc) 200 { 201 u_char csr0; 202 203 csr0 = sbni_inb(sc, CSR0); 204 if (csr0 != 0xff && csr0 != 0x00) { 205 csr0 &= ~EN_INT; 206 if (csr0 & BU_EMP) 207 csr0 |= EN_INT; 208 209 if (VALID_DECODER & (1 << (csr0 >> 4))) 210 return (0); 211 } 212 213 return (ENXIO); 214 } 215 216 217 /* 218 * Install interface into kernel networking data structures 219 */ 220 void 221 sbni_attach(struct sbni_softc *sc, int unit, struct sbni_flags flags) 222 { 223 struct ifnet *ifp; 224 u_char csr0; 225 226 ifp = sc->ifp = if_alloc(IFT_ETHER); 227 if (ifp == NULL) 228 panic("sbni%d: can not if_alloc()", unit); 229 sbni_outb(sc, CSR0, 0); 230 set_initial_values(sc, flags); 231 232 callout_handle_init(&sc->wch); 233 /* Initialize ifnet structure */ 234 ifp->if_softc = sc; 235 if_initname(ifp, "sbni", unit); 236 ifp->if_init = sbni_init; 237 ifp->if_start = sbni_start; 238 ifp->if_ioctl = sbni_ioctl; 239 ifp->if_watchdog = sbni_watchdog; 240 ifp->if_snd.ifq_maxlen = IFQ_MAXLEN; 241 242 /* report real baud rate */ 243 csr0 = sbni_inb(sc, CSR0); 244 ifp->if_baudrate = 245 (csr0 & 0x01 ? 500000 : 2000000) / (1 << flags.rate); 246 247 ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST | 248 IFF_NEEDSGIANT; 249 ether_ifattach(ifp, sc->enaddr); 250 /* device attach does transition from UNCONFIGURED to IDLE state */ 251 252 if_printf(ifp, "speed %ld, rxl ", ifp->if_baudrate); 253 if (sc->delta_rxl) 254 printf("auto\n"); 255 else 256 printf("%d (fixed)\n", sc->cur_rxl_index); 257 } 258 259 /* -------------------------------------------------------------------------- */ 260 261 static void 262 sbni_init(void *xsc) 263 { 264 struct sbni_softc *sc; 265 struct ifnet *ifp; 266 int s; 267 268 sc = (struct sbni_softc *)xsc; 269 ifp = sc->ifp; 270 271 /* 272 * kludge to avoid multiple initialization when more than once 273 * protocols configured 274 */ 275 if (ifp->if_drv_flags & IFF_DRV_RUNNING) 276 return; 277 278 s = splimp(); 279 ifp->if_timer = 0; 280 card_start(sc); 281 sc->wch = timeout(sbni_timeout, sc, hz/SBNI_HZ); 282 283 ifp->if_drv_flags |= IFF_DRV_RUNNING; 284 ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 285 286 /* attempt to start output */ 287 sbni_start(ifp); 288 splx(s); 289 } 290 291 292 static void 293 sbni_start(struct ifnet *ifp) 294 { 295 struct sbni_softc *sc = ifp->if_softc; 296 if (sc->tx_frameno == 0) 297 prepare_to_send(sc); 298 } 299 300 301 static void 302 sbni_stop(struct sbni_softc *sc) 303 { 304 sbni_outb(sc, CSR0, 0); 305 drop_xmit_queue(sc); 306 307 if (sc->rx_buf_p) { 308 m_freem(sc->rx_buf_p); 309 sc->rx_buf_p = NULL; 310 } 311 312 untimeout(sbni_timeout, sc, sc->wch); 313 sc->wch.callout = NULL; 314 } 315 316 /* -------------------------------------------------------------------------- */ 317 318 /* interrupt handler */ 319 320 /* 321 * SBNI12D-10, -11/ISA boards within "common interrupt" mode could not 322 * be looked as two independent single-channel devices. Every channel seems 323 * as Ethernet interface but interrupt handler must be common. Really, first 324 * channel ("master") driver only registers the handler. In it's struct softc 325 * it has got pointer to "slave" channel's struct softc and handles that's 326 * interrupts too. 327 * softc of successfully attached ISA SBNI boards is linked to list. 328 * While next board driver is initialized, it scans this list. If one 329 * has found softc with same irq and ioaddr different by 4 then it assumes 330 * this board to be "master". 331 */ 332 333 void 334 sbni_intr(void *arg) 335 { 336 struct sbni_softc *sc; 337 int repeat; 338 339 sc = (struct sbni_softc *)arg; 340 341 do { 342 repeat = 0; 343 if (sbni_inb(sc, CSR0) & (RC_RDY | TR_RDY)) { 344 handle_channel(sc); 345 repeat = 1; 346 } 347 if (sc->slave_sc && /* second channel present */ 348 (sbni_inb(sc->slave_sc, CSR0) & (RC_RDY | TR_RDY))) { 349 handle_channel(sc->slave_sc); 350 repeat = 1; 351 } 352 } while (repeat); 353 } 354 355 356 static void 357 handle_channel(struct sbni_softc *sc) 358 { 359 int req_ans; 360 u_char csr0; 361 362 sbni_outb(sc, CSR0, (sbni_inb(sc, CSR0) & ~EN_INT) | TR_REQ); 363 364 sc->timer_ticks = CHANGE_LEVEL_START_TICKS; 365 for (;;) { 366 csr0 = sbni_inb(sc, CSR0); 367 if ((csr0 & (RC_RDY | TR_RDY)) == 0) 368 break; 369 370 req_ans = !(sc->state & FL_PREV_OK); 371 372 if (csr0 & RC_RDY) 373 req_ans = recv_frame(sc); 374 375 /* 376 * TR_RDY always equals 1 here because we have owned the marker, 377 * and we set TR_REQ when disabled interrupts 378 */ 379 csr0 = sbni_inb(sc, CSR0); 380 if ((csr0 & TR_RDY) == 0 || (csr0 & RC_RDY) != 0) 381 printf("sbni: internal error!\n"); 382 383 /* if state & FL_NEED_RESEND != 0 then tx_frameno != 0 */ 384 if (req_ans || sc->tx_frameno != 0) 385 send_frame(sc); 386 else { 387 /* send the marker without any data */ 388 sbni_outb(sc, CSR0, sbni_inb(sc, CSR0) & ~TR_REQ); 389 } 390 } 391 392 sbni_outb(sc, CSR0, sbni_inb(sc, CSR0) | EN_INT); 393 } 394 395 396 /* 397 * Routine returns 1 if it need to acknoweledge received frame. 398 * Empty frame received without errors won't be acknoweledged. 399 */ 400 401 static int 402 recv_frame(struct sbni_softc *sc) 403 { 404 u_int32_t crc; 405 u_int framelen, frameno, ack; 406 u_int is_first, frame_ok; 407 408 crc = CRC32_INITIAL; 409 if (check_fhdr(sc, &framelen, &frameno, &ack, &is_first, &crc)) { 410 frame_ok = framelen > 4 ? 411 upload_data(sc, framelen, frameno, is_first, crc) : 412 skip_tail(sc, framelen, crc); 413 if (frame_ok) 414 interpret_ack(sc, ack); 415 } else { 416 framelen = 0; 417 frame_ok = 0; 418 } 419 420 sbni_outb(sc, CSR0, sbni_inb(sc, CSR0) ^ CT_ZER); 421 if (frame_ok) { 422 sc->state |= FL_PREV_OK; 423 if (framelen > 4) 424 sc->in_stats.all_rx_number++; 425 } else { 426 sc->state &= ~FL_PREV_OK; 427 change_level(sc); 428 sc->in_stats.all_rx_number++; 429 sc->in_stats.bad_rx_number++; 430 } 431 432 return (!frame_ok || framelen > 4); 433 } 434 435 436 static void 437 send_frame(struct sbni_softc *sc) 438 { 439 u_int32_t crc; 440 u_char csr0; 441 442 crc = CRC32_INITIAL; 443 if (sc->state & FL_NEED_RESEND) { 444 445 /* if frame was sended but not ACK'ed - resend it */ 446 if (sc->trans_errors) { 447 sc->trans_errors--; 448 if (sc->framelen != 0) 449 sc->in_stats.resend_tx_number++; 450 } else { 451 /* cannot xmit with many attempts */ 452 drop_xmit_queue(sc); 453 goto do_send; 454 } 455 } else 456 sc->trans_errors = TR_ERROR_COUNT; 457 458 send_frame_header(sc, &crc); 459 sc->state |= FL_NEED_RESEND; 460 /* 461 * FL_NEED_RESEND will be cleared after ACK, but if empty 462 * frame sended then in prepare_to_send next frame 463 */ 464 465 466 if (sc->framelen) { 467 download_data(sc, &crc); 468 sc->in_stats.all_tx_number++; 469 sc->state |= FL_WAIT_ACK; 470 } 471 472 sbni_outsb(sc, (u_char *)&crc, sizeof crc); 473 474 do_send: 475 csr0 = sbni_inb(sc, CSR0); 476 sbni_outb(sc, CSR0, csr0 & ~TR_REQ); 477 478 if (sc->tx_frameno) { 479 /* next frame exists - request to send */ 480 sbni_outb(sc, CSR0, csr0 | TR_REQ); 481 } 482 } 483 484 485 static void 486 download_data(struct sbni_softc *sc, u_int32_t *crc_p) 487 { 488 struct mbuf *m; 489 caddr_t data_p; 490 u_int data_len, pos, slice; 491 492 data_p = NULL; /* initialized to avoid warn */ 493 pos = 0; 494 495 for (m = sc->tx_buf_p; m != NULL && pos < sc->pktlen; m = m->m_next) { 496 if (pos + m->m_len > sc->outpos) { 497 data_len = m->m_len - (sc->outpos - pos); 498 data_p = mtod(m, caddr_t) + (sc->outpos - pos); 499 500 goto do_copy; 501 } else 502 pos += m->m_len; 503 } 504 505 data_len = 0; 506 507 do_copy: 508 pos = 0; 509 do { 510 if (data_len) { 511 slice = min(data_len, sc->framelen - pos); 512 sbni_outsb(sc, data_p, slice); 513 *crc_p = calc_crc32(*crc_p, data_p, slice); 514 515 pos += slice; 516 if (data_len -= slice) 517 data_p += slice; 518 else { 519 do { 520 m = m->m_next; 521 } while (m != NULL && m->m_len == 0); 522 523 if (m) { 524 data_len = m->m_len; 525 data_p = mtod(m, caddr_t); 526 } 527 } 528 } else { 529 /* frame too short - zero padding */ 530 531 pos = sc->framelen - pos; 532 while (pos--) { 533 sbni_outb(sc, DAT, 0); 534 *crc_p = CRC32(0, *crc_p); 535 } 536 return; 537 } 538 } while (pos < sc->framelen); 539 } 540 541 542 static int 543 upload_data(struct sbni_softc *sc, u_int framelen, u_int frameno, 544 u_int is_first, u_int32_t crc) 545 { 546 int frame_ok; 547 548 if (is_first) { 549 sc->wait_frameno = frameno; 550 sc->inppos = 0; 551 } 552 553 if (sc->wait_frameno == frameno) { 554 555 if (sc->inppos + framelen <= ETHER_MAX_LEN) { 556 frame_ok = append_frame_to_pkt(sc, framelen, crc); 557 558 /* 559 * if CRC is right but framelen incorrect then transmitter 560 * error was occured... drop entire packet 561 */ 562 } else if ((frame_ok = skip_tail(sc, framelen, crc)) != 0) { 563 sc->wait_frameno = 0; 564 sc->inppos = 0; 565 sc->ifp->if_ierrors++; 566 /* now skip all frames until is_first != 0 */ 567 } 568 } else 569 frame_ok = skip_tail(sc, framelen, crc); 570 571 if (is_first && !frame_ok) { 572 /* 573 * Frame has been violated, but we have stored 574 * is_first already... Drop entire packet. 575 */ 576 sc->wait_frameno = 0; 577 sc->ifp->if_ierrors++; 578 } 579 580 return (frame_ok); 581 } 582 583 584 static __inline void send_complete(struct sbni_softc *); 585 586 static __inline void 587 send_complete(struct sbni_softc *sc) 588 { 589 m_freem(sc->tx_buf_p); 590 sc->tx_buf_p = NULL; 591 sc->ifp->if_opackets++; 592 } 593 594 595 static void 596 interpret_ack(struct sbni_softc *sc, u_int ack) 597 { 598 if (ack == FRAME_SENT_OK) { 599 sc->state &= ~FL_NEED_RESEND; 600 601 if (sc->state & FL_WAIT_ACK) { 602 sc->outpos += sc->framelen; 603 604 if (--sc->tx_frameno) { 605 sc->framelen = min( 606 sc->maxframe, sc->pktlen - sc->outpos); 607 } else { 608 send_complete(sc); 609 prepare_to_send(sc); 610 } 611 } 612 } 613 614 sc->state &= ~FL_WAIT_ACK; 615 } 616 617 618 /* 619 * Glue received frame with previous fragments of packet. 620 * Indicate packet when last frame would be accepted. 621 */ 622 623 static int 624 append_frame_to_pkt(struct sbni_softc *sc, u_int framelen, u_int32_t crc) 625 { 626 caddr_t p; 627 628 if (sc->inppos + framelen > ETHER_MAX_LEN) 629 return (0); 630 631 if (!sc->rx_buf_p && !get_rx_buf(sc)) 632 return (0); 633 634 p = sc->rx_buf_p->m_data + sc->inppos; 635 sbni_insb(sc, p, framelen); 636 if (calc_crc32(crc, p, framelen) != CRC32_REMAINDER) 637 return (0); 638 639 sc->inppos += framelen - 4; 640 if (--sc->wait_frameno == 0) { /* last frame received */ 641 indicate_pkt(sc); 642 sc->ifp->if_ipackets++; 643 } 644 645 return (1); 646 } 647 648 649 /* 650 * Prepare to start output on adapter. Current priority must be set to splimp 651 * before this routine is called. 652 * Transmitter will be actually activated when marker has been accepted. 653 */ 654 655 static void 656 prepare_to_send(struct sbni_softc *sc) 657 { 658 struct mbuf *m; 659 u_int len; 660 661 /* sc->tx_buf_p == NULL here! */ 662 if (sc->tx_buf_p) 663 printf("sbni: memory leak!\n"); 664 665 sc->outpos = 0; 666 sc->state &= ~(FL_WAIT_ACK | FL_NEED_RESEND); 667 668 for (;;) { 669 IF_DEQUEUE(&sc->ifp->if_snd, sc->tx_buf_p); 670 if (!sc->tx_buf_p) { 671 /* nothing to transmit... */ 672 sc->pktlen = 0; 673 sc->tx_frameno = 0; 674 sc->framelen = 0; 675 sc->ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 676 return; 677 } 678 679 for (len = 0, m = sc->tx_buf_p; m; m = m->m_next) 680 len += m->m_len; 681 682 if (len != 0) 683 break; 684 m_freem(sc->tx_buf_p); 685 } 686 687 if (len < SBNI_MIN_LEN) 688 len = SBNI_MIN_LEN; 689 690 sc->pktlen = len; 691 sc->tx_frameno = (len + sc->maxframe - 1) / sc->maxframe; 692 sc->framelen = min(len, sc->maxframe); 693 694 sbni_outb(sc, CSR0, sbni_inb(sc, CSR0) | TR_REQ); 695 sc->ifp->if_drv_flags |= IFF_DRV_OACTIVE; 696 BPF_MTAP(sc->ifp, sc->tx_buf_p); 697 } 698 699 700 static void 701 drop_xmit_queue(struct sbni_softc *sc) 702 { 703 struct mbuf *m; 704 705 if (sc->tx_buf_p) { 706 m_freem(sc->tx_buf_p); 707 sc->tx_buf_p = NULL; 708 sc->ifp->if_oerrors++; 709 } 710 711 for (;;) { 712 IF_DEQUEUE(&sc->ifp->if_snd, m); 713 if (m == NULL) 714 break; 715 m_freem(m); 716 sc->ifp->if_oerrors++; 717 } 718 719 sc->tx_frameno = 0; 720 sc->framelen = 0; 721 sc->outpos = 0; 722 sc->state &= ~(FL_WAIT_ACK | FL_NEED_RESEND); 723 sc->ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 724 } 725 726 727 static void 728 send_frame_header(struct sbni_softc *sc, u_int32_t *crc_p) 729 { 730 u_int32_t crc; 731 u_int len_field; 732 u_char value; 733 734 crc = *crc_p; 735 len_field = sc->framelen + 6; /* CRC + frameno + reserved */ 736 737 if (sc->state & FL_NEED_RESEND) 738 len_field |= FRAME_RETRY; /* non-first attempt... */ 739 740 if (sc->outpos == 0) 741 len_field |= FRAME_FIRST; 742 743 len_field |= (sc->state & FL_PREV_OK) ? FRAME_SENT_OK : FRAME_SENT_BAD; 744 sbni_outb(sc, DAT, SBNI_SIG); 745 746 value = (u_char)len_field; 747 sbni_outb(sc, DAT, value); 748 crc = CRC32(value, crc); 749 value = (u_char)(len_field >> 8); 750 sbni_outb(sc, DAT, value); 751 crc = CRC32(value, crc); 752 753 sbni_outb(sc, DAT, sc->tx_frameno); 754 crc = CRC32(sc->tx_frameno, crc); 755 sbni_outb(sc, DAT, 0); 756 crc = CRC32(0, crc); 757 *crc_p = crc; 758 } 759 760 761 /* 762 * if frame tail not needed (incorrect number or received twice), 763 * it won't store, but CRC will be calculated 764 */ 765 766 static int 767 skip_tail(struct sbni_softc *sc, u_int tail_len, u_int32_t crc) 768 { 769 while (tail_len--) 770 crc = CRC32(sbni_inb(sc, DAT), crc); 771 772 return (crc == CRC32_REMAINDER); 773 } 774 775 776 static int 777 check_fhdr(struct sbni_softc *sc, u_int *framelen, u_int *frameno, 778 u_int *ack, u_int *is_first, u_int32_t *crc_p) 779 { 780 u_int32_t crc; 781 u_char value; 782 783 crc = *crc_p; 784 if (sbni_inb(sc, DAT) != SBNI_SIG) 785 return (0); 786 787 value = sbni_inb(sc, DAT); 788 *framelen = (u_int)value; 789 crc = CRC32(value, crc); 790 value = sbni_inb(sc, DAT); 791 *framelen |= ((u_int)value) << 8; 792 crc = CRC32(value, crc); 793 794 *ack = *framelen & FRAME_ACK_MASK; 795 *is_first = (*framelen & FRAME_FIRST) != 0; 796 797 if ((*framelen &= FRAME_LEN_MASK) < 6 || *framelen > SBNI_MAX_FRAME - 3) 798 return (0); 799 800 value = sbni_inb(sc, DAT); 801 *frameno = (u_int)value; 802 crc = CRC32(value, crc); 803 804 crc = CRC32(sbni_inb(sc, DAT), crc); /* reserved byte */ 805 *framelen -= 2; 806 807 *crc_p = crc; 808 return (1); 809 } 810 811 812 static int 813 get_rx_buf(struct sbni_softc *sc) 814 { 815 struct mbuf *m; 816 817 MGETHDR(m, M_DONTWAIT, MT_DATA); 818 if (m == NULL) { 819 if_printf(sc->ifp, "cannot allocate header mbuf\n"); 820 return (0); 821 } 822 823 /* 824 * We always put the received packet in a single buffer - 825 * either with just an mbuf header or in a cluster attached 826 * to the header. The +2 is to compensate for the alignment 827 * fixup below. 828 */ 829 if (ETHER_MAX_LEN + 2 > MHLEN) { 830 /* Attach an mbuf cluster */ 831 MCLGET(m, M_DONTWAIT); 832 if ((m->m_flags & M_EXT) == 0) { 833 m_freem(m); 834 return (0); 835 } 836 } 837 m->m_pkthdr.len = m->m_len = ETHER_MAX_LEN + 2; 838 839 /* 840 * The +2 is to longword align the start of the real packet. 841 * (sizeof ether_header == 14) 842 * This is important for NFS. 843 */ 844 m_adj(m, 2); 845 sc->rx_buf_p = m; 846 return (1); 847 } 848 849 850 static void 851 indicate_pkt(struct sbni_softc *sc) 852 { 853 struct ifnet *ifp = sc->ifp; 854 struct mbuf *m; 855 856 m = sc->rx_buf_p; 857 m->m_pkthdr.rcvif = ifp; 858 m->m_pkthdr.len = m->m_len = sc->inppos; 859 860 (*ifp->if_input)(ifp, m); 861 sc->rx_buf_p = NULL; 862 } 863 864 /* -------------------------------------------------------------------------- */ 865 866 /* 867 * Routine checks periodically wire activity and regenerates marker if 868 * connect was inactive for a long time. 869 */ 870 871 static void 872 sbni_timeout(void *xsc) 873 { 874 struct sbni_softc *sc; 875 int s; 876 u_char csr0; 877 878 sc = (struct sbni_softc *)xsc; 879 s = splimp(); 880 881 csr0 = sbni_inb(sc, CSR0); 882 if (csr0 & RC_CHK) { 883 884 if (sc->timer_ticks) { 885 if (csr0 & (RC_RDY | BU_EMP)) 886 /* receiving not active */ 887 sc->timer_ticks--; 888 } else { 889 sc->in_stats.timeout_number++; 890 if (sc->delta_rxl) 891 timeout_change_level(sc); 892 893 sbni_outb(sc, CSR1, *(u_char *)&sc->csr1 | PR_RES); 894 csr0 = sbni_inb(sc, CSR0); 895 } 896 } 897 898 sbni_outb(sc, CSR0, csr0 | RC_CHK); 899 sc->wch = timeout(sbni_timeout, sc, hz/SBNI_HZ); 900 splx(s); 901 } 902 903 /* -------------------------------------------------------------------------- */ 904 905 static void 906 card_start(struct sbni_softc *sc) 907 { 908 sc->timer_ticks = CHANGE_LEVEL_START_TICKS; 909 sc->state &= ~(FL_WAIT_ACK | FL_NEED_RESEND); 910 sc->state |= FL_PREV_OK; 911 912 sc->inppos = 0; 913 sc->wait_frameno = 0; 914 915 sbni_outb(sc, CSR1, *(u_char *)&sc->csr1 | PR_RES); 916 sbni_outb(sc, CSR0, EN_INT); 917 } 918 919 /* -------------------------------------------------------------------------- */ 920 921 /* 922 * Device timeout/watchdog routine. Entered if the device neglects to 923 * generate an interrupt after a transmit has been started on it. 924 */ 925 926 static void 927 sbni_watchdog(struct ifnet *ifp) 928 { 929 log(LOG_ERR, "%s: device timeout\n", ifp->if_xname); 930 ifp->if_oerrors++; 931 } 932 933 934 static u_char rxl_tab[] = { 935 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x08, 936 0x0a, 0x0c, 0x0f, 0x16, 0x18, 0x1a, 0x1c, 0x1f 937 }; 938 939 #define SIZE_OF_TIMEOUT_RXL_TAB 4 940 static u_char timeout_rxl_tab[] = { 941 0x03, 0x05, 0x08, 0x0b 942 }; 943 944 static void 945 set_initial_values(struct sbni_softc *sc, struct sbni_flags flags) 946 { 947 if (flags.fixed_rxl) { 948 sc->delta_rxl = 0; /* disable receive level autodetection */ 949 sc->cur_rxl_index = flags.rxl; 950 } else { 951 sc->delta_rxl = DEF_RXL_DELTA; 952 sc->cur_rxl_index = DEF_RXL; 953 } 954 955 sc->csr1.rate = flags.fixed_rate ? flags.rate : DEFAULT_RATE; 956 sc->csr1.rxl = rxl_tab[sc->cur_rxl_index]; 957 sc->maxframe = DEFAULT_FRAME_LEN; 958 959 /* 960 * generate Ethernet address (0x00ff01xxxxxx) 961 */ 962 *(u_int16_t *) sc->enaddr = htons(0x00ff); 963 if (flags.mac_addr) { 964 *(u_int32_t *) (sc->enaddr + 2) = 965 htonl(flags.mac_addr | 0x01000000); 966 } else { 967 *(u_char *) (sc->enaddr + 2) = 0x01; 968 read_random(sc->enaddr + 3, 3); 969 } 970 } 971 972 973 #ifdef SBNI_DUAL_COMPOUND 974 975 struct sbni_softc * 976 connect_to_master(struct sbni_softc *sc) 977 { 978 struct sbni_softc *p, *p_prev; 979 980 for (p = sbni_headlist, p_prev = NULL; p; p_prev = p, p = p->link) { 981 if (rman_get_start(p->io_res) == rman_get_start(sc->io_res) + 4 || 982 rman_get_start(p->io_res) == rman_get_start(sc->io_res) - 4) { 983 p->slave_sc = sc; 984 if (p_prev) 985 p_prev->link = p->link; 986 else 987 sbni_headlist = p->link; 988 return p; 989 } 990 } 991 992 return (NULL); 993 } 994 995 #endif /* SBNI_DUAL_COMPOUND */ 996 997 998 /* Receive level auto-selection */ 999 1000 static void 1001 change_level(struct sbni_softc *sc) 1002 { 1003 if (sc->delta_rxl == 0) /* do not auto-negotiate RxL */ 1004 return; 1005 1006 if (sc->cur_rxl_index == 0) 1007 sc->delta_rxl = 1; 1008 else if (sc->cur_rxl_index == 15) 1009 sc->delta_rxl = -1; 1010 else if (sc->cur_rxl_rcvd < sc->prev_rxl_rcvd) 1011 sc->delta_rxl = -sc->delta_rxl; 1012 1013 sc->csr1.rxl = rxl_tab[sc->cur_rxl_index += sc->delta_rxl]; 1014 sbni_inb(sc, CSR0); /* it needed for PCI cards */ 1015 sbni_outb(sc, CSR1, *(u_char *)&sc->csr1); 1016 1017 sc->prev_rxl_rcvd = sc->cur_rxl_rcvd; 1018 sc->cur_rxl_rcvd = 0; 1019 } 1020 1021 1022 static void 1023 timeout_change_level(struct sbni_softc *sc) 1024 { 1025 sc->cur_rxl_index = timeout_rxl_tab[sc->timeout_rxl]; 1026 if (++sc->timeout_rxl >= 4) 1027 sc->timeout_rxl = 0; 1028 1029 sc->csr1.rxl = rxl_tab[sc->cur_rxl_index]; 1030 sbni_inb(sc, CSR0); 1031 sbni_outb(sc, CSR1, *(u_char *)&sc->csr1); 1032 1033 sc->prev_rxl_rcvd = sc->cur_rxl_rcvd; 1034 sc->cur_rxl_rcvd = 0; 1035 } 1036 1037 /* -------------------------------------------------------------------------- */ 1038 1039 /* 1040 * Process an ioctl request. This code needs some work - it looks 1041 * pretty ugly. 1042 */ 1043 1044 static int 1045 sbni_ioctl(struct ifnet *ifp, u_long command, caddr_t data) 1046 { 1047 struct sbni_softc *sc; 1048 struct ifreq *ifr; 1049 struct thread *td; 1050 struct sbni_in_stats *in_stats; 1051 struct sbni_flags flags; 1052 int error, s; 1053 1054 sc = ifp->if_softc; 1055 ifr = (struct ifreq *)data; 1056 td = curthread; 1057 error = 0; 1058 1059 s = splimp(); 1060 1061 switch (command) { 1062 case SIOCSIFFLAGS: 1063 /* 1064 * If the interface is marked up and stopped, then start it. 1065 * If it is marked down and running, then stop it. 1066 */ 1067 if (ifp->if_flags & IFF_UP) { 1068 if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) 1069 sbni_init(sc); 1070 } else { 1071 if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 1072 sbni_stop(sc); 1073 ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 1074 } 1075 } 1076 break; 1077 1078 case SIOCADDMULTI: 1079 case SIOCDELMULTI: 1080 /* 1081 * Multicast list has changed; set the hardware filter 1082 * accordingly. 1083 */ 1084 error = 0; 1085 /* if (ifr == NULL) 1086 error = EAFNOSUPPORT; */ 1087 break; 1088 1089 case SIOCSIFMTU: 1090 if (ifr->ifr_mtu > ETHERMTU) 1091 error = EINVAL; 1092 else 1093 ifp->if_mtu = ifr->ifr_mtu; 1094 break; 1095 1096 /* 1097 * SBNI specific ioctl 1098 */ 1099 case SIOCGHWFLAGS: /* get flags */ 1100 bcopy((caddr_t)IF_LLADDR(sc->ifp)+3, (caddr_t) &flags, 3); 1101 flags.rxl = sc->cur_rxl_index; 1102 flags.rate = sc->csr1.rate; 1103 flags.fixed_rxl = (sc->delta_rxl == 0); 1104 flags.fixed_rate = 1; 1105 ifr->ifr_data = *(caddr_t*) &flags; 1106 break; 1107 1108 case SIOCGINSTATS: 1109 in_stats = (struct sbni_in_stats *)ifr->ifr_data; 1110 bcopy((void *)(&(sc->in_stats)), (void *)in_stats, 1111 sizeof(struct sbni_in_stats)); 1112 break; 1113 1114 case SIOCSHWFLAGS: /* set flags */ 1115 /* root only */ 1116 error = priv_check(td, PRIV_DRIVER); 1117 if (error) 1118 break; 1119 flags = *(struct sbni_flags*)&ifr->ifr_data; 1120 if (flags.fixed_rxl) { 1121 sc->delta_rxl = 0; 1122 sc->cur_rxl_index = flags.rxl; 1123 } else { 1124 sc->delta_rxl = DEF_RXL_DELTA; 1125 sc->cur_rxl_index = DEF_RXL; 1126 } 1127 sc->csr1.rxl = rxl_tab[sc->cur_rxl_index]; 1128 sc->csr1.rate = flags.fixed_rate ? flags.rate : DEFAULT_RATE; 1129 if (flags.mac_addr) 1130 bcopy((caddr_t) &flags, 1131 (caddr_t) IF_LLADDR(sc->ifp)+3, 3); 1132 1133 /* Don't be afraid... */ 1134 sbni_outb(sc, CSR1, *(char*)(&sc->csr1) | PR_RES); 1135 break; 1136 1137 case SIOCRINSTATS: 1138 if (!(error = priv_check(td, PRIV_DRIVER))) /* root only */ 1139 bzero(&sc->in_stats, sizeof(struct sbni_in_stats)); 1140 break; 1141 1142 default: 1143 error = ether_ioctl(ifp, command, data); 1144 break; 1145 } 1146 1147 splx(s); 1148 return (error); 1149 } 1150 1151 /* -------------------------------------------------------------------------- */ 1152 1153 #ifdef ASM_CRC 1154 1155 static u_int32_t 1156 calc_crc32(u_int32_t crc, caddr_t p, u_int len) 1157 { 1158 register u_int32_t _crc __asm ("ax"); 1159 _crc = crc; 1160 1161 __asm __volatile ( 1162 "xorl %%ebx, %%ebx\n" 1163 "movl %1, %%esi\n" 1164 "movl %2, %%ecx\n" 1165 "movl $crc32tab, %%edi\n" 1166 "shrl $2, %%ecx\n" 1167 "jz 1f\n" 1168 1169 ".align 4\n" 1170 "0:\n" 1171 "movb %%al, %%bl\n" 1172 "movl (%%esi), %%edx\n" 1173 "shrl $8, %%eax\n" 1174 "xorb %%dl, %%bl\n" 1175 "shrl $8, %%edx\n" 1176 "xorl (%%edi,%%ebx,4), %%eax\n" 1177 1178 "movb %%al, %%bl\n" 1179 "shrl $8, %%eax\n" 1180 "xorb %%dl, %%bl\n" 1181 "shrl $8, %%edx\n" 1182 "xorl (%%edi,%%ebx,4), %%eax\n" 1183 1184 "movb %%al, %%bl\n" 1185 "shrl $8, %%eax\n" 1186 "xorb %%dl, %%bl\n" 1187 "movb %%dh, %%dl\n" 1188 "xorl (%%edi,%%ebx,4), %%eax\n" 1189 1190 "movb %%al, %%bl\n" 1191 "shrl $8, %%eax\n" 1192 "xorb %%dl, %%bl\n" 1193 "addl $4, %%esi\n" 1194 "xorl (%%edi,%%ebx,4), %%eax\n" 1195 1196 "decl %%ecx\n" 1197 "jnz 0b\n" 1198 1199 "1:\n" 1200 "movl %2, %%ecx\n" 1201 "andl $3, %%ecx\n" 1202 "jz 2f\n" 1203 1204 "movb %%al, %%bl\n" 1205 "shrl $8, %%eax\n" 1206 "xorb (%%esi), %%bl\n" 1207 "xorl (%%edi,%%ebx,4), %%eax\n" 1208 1209 "decl %%ecx\n" 1210 "jz 2f\n" 1211 1212 "movb %%al, %%bl\n" 1213 "shrl $8, %%eax\n" 1214 "xorb 1(%%esi), %%bl\n" 1215 "xorl (%%edi,%%ebx,4), %%eax\n" 1216 1217 "decl %%ecx\n" 1218 "jz 2f\n" 1219 1220 "movb %%al, %%bl\n" 1221 "shrl $8, %%eax\n" 1222 "xorb 2(%%esi), %%bl\n" 1223 "xorl (%%edi,%%ebx,4), %%eax\n" 1224 "2:\n" 1225 : "=a" (_crc) 1226 : "g" (p), "g" (len) 1227 : "bx", "cx", "dx", "si", "di" 1228 ); 1229 1230 return (_crc); 1231 } 1232 1233 #else /* ASM_CRC */ 1234 1235 static u_int32_t 1236 calc_crc32(u_int32_t crc, caddr_t p, u_int len) 1237 { 1238 while (len--) 1239 crc = CRC32(*p++, crc); 1240 1241 return (crc); 1242 } 1243 1244 #endif /* ASM_CRC */ 1245 1246 1247 static u_int32_t crc32tab[] __aligned(8) = { 1248 0xD202EF8D, 0xA505DF1B, 0x3C0C8EA1, 0x4B0BBE37, 1249 0xD56F2B94, 0xA2681B02, 0x3B614AB8, 0x4C667A2E, 1250 0xDCD967BF, 0xABDE5729, 0x32D70693, 0x45D03605, 1251 0xDBB4A3A6, 0xACB39330, 0x35BAC28A, 0x42BDF21C, 1252 0xCFB5FFE9, 0xB8B2CF7F, 0x21BB9EC5, 0x56BCAE53, 1253 0xC8D83BF0, 0xBFDF0B66, 0x26D65ADC, 0x51D16A4A, 1254 0xC16E77DB, 0xB669474D, 0x2F6016F7, 0x58672661, 1255 0xC603B3C2, 0xB1048354, 0x280DD2EE, 0x5F0AE278, 1256 0xE96CCF45, 0x9E6BFFD3, 0x0762AE69, 0x70659EFF, 1257 0xEE010B5C, 0x99063BCA, 0x000F6A70, 0x77085AE6, 1258 0xE7B74777, 0x90B077E1, 0x09B9265B, 0x7EBE16CD, 1259 0xE0DA836E, 0x97DDB3F8, 0x0ED4E242, 0x79D3D2D4, 1260 0xF4DBDF21, 0x83DCEFB7, 0x1AD5BE0D, 0x6DD28E9B, 1261 0xF3B61B38, 0x84B12BAE, 0x1DB87A14, 0x6ABF4A82, 1262 0xFA005713, 0x8D076785, 0x140E363F, 0x630906A9, 1263 0xFD6D930A, 0x8A6AA39C, 0x1363F226, 0x6464C2B0, 1264 0xA4DEAE1D, 0xD3D99E8B, 0x4AD0CF31, 0x3DD7FFA7, 1265 0xA3B36A04, 0xD4B45A92, 0x4DBD0B28, 0x3ABA3BBE, 1266 0xAA05262F, 0xDD0216B9, 0x440B4703, 0x330C7795, 1267 0xAD68E236, 0xDA6FD2A0, 0x4366831A, 0x3461B38C, 1268 0xB969BE79, 0xCE6E8EEF, 0x5767DF55, 0x2060EFC3, 1269 0xBE047A60, 0xC9034AF6, 0x500A1B4C, 0x270D2BDA, 1270 0xB7B2364B, 0xC0B506DD, 0x59BC5767, 0x2EBB67F1, 1271 0xB0DFF252, 0xC7D8C2C4, 0x5ED1937E, 0x29D6A3E8, 1272 0x9FB08ED5, 0xE8B7BE43, 0x71BEEFF9, 0x06B9DF6F, 1273 0x98DD4ACC, 0xEFDA7A5A, 0x76D32BE0, 0x01D41B76, 1274 0x916B06E7, 0xE66C3671, 0x7F6567CB, 0x0862575D, 1275 0x9606C2FE, 0xE101F268, 0x7808A3D2, 0x0F0F9344, 1276 0x82079EB1, 0xF500AE27, 0x6C09FF9D, 0x1B0ECF0B, 1277 0x856A5AA8, 0xF26D6A3E, 0x6B643B84, 0x1C630B12, 1278 0x8CDC1683, 0xFBDB2615, 0x62D277AF, 0x15D54739, 1279 0x8BB1D29A, 0xFCB6E20C, 0x65BFB3B6, 0x12B88320, 1280 0x3FBA6CAD, 0x48BD5C3B, 0xD1B40D81, 0xA6B33D17, 1281 0x38D7A8B4, 0x4FD09822, 0xD6D9C998, 0xA1DEF90E, 1282 0x3161E49F, 0x4666D409, 0xDF6F85B3, 0xA868B525, 1283 0x360C2086, 0x410B1010, 0xD80241AA, 0xAF05713C, 1284 0x220D7CC9, 0x550A4C5F, 0xCC031DE5, 0xBB042D73, 1285 0x2560B8D0, 0x52678846, 0xCB6ED9FC, 0xBC69E96A, 1286 0x2CD6F4FB, 0x5BD1C46D, 0xC2D895D7, 0xB5DFA541, 1287 0x2BBB30E2, 0x5CBC0074, 0xC5B551CE, 0xB2B26158, 1288 0x04D44C65, 0x73D37CF3, 0xEADA2D49, 0x9DDD1DDF, 1289 0x03B9887C, 0x74BEB8EA, 0xEDB7E950, 0x9AB0D9C6, 1290 0x0A0FC457, 0x7D08F4C1, 0xE401A57B, 0x930695ED, 1291 0x0D62004E, 0x7A6530D8, 0xE36C6162, 0x946B51F4, 1292 0x19635C01, 0x6E646C97, 0xF76D3D2D, 0x806A0DBB, 1293 0x1E0E9818, 0x6909A88E, 0xF000F934, 0x8707C9A2, 1294 0x17B8D433, 0x60BFE4A5, 0xF9B6B51F, 0x8EB18589, 1295 0x10D5102A, 0x67D220BC, 0xFEDB7106, 0x89DC4190, 1296 0x49662D3D, 0x3E611DAB, 0xA7684C11, 0xD06F7C87, 1297 0x4E0BE924, 0x390CD9B2, 0xA0058808, 0xD702B89E, 1298 0x47BDA50F, 0x30BA9599, 0xA9B3C423, 0xDEB4F4B5, 1299 0x40D06116, 0x37D75180, 0xAEDE003A, 0xD9D930AC, 1300 0x54D13D59, 0x23D60DCF, 0xBADF5C75, 0xCDD86CE3, 1301 0x53BCF940, 0x24BBC9D6, 0xBDB2986C, 0xCAB5A8FA, 1302 0x5A0AB56B, 0x2D0D85FD, 0xB404D447, 0xC303E4D1, 1303 0x5D677172, 0x2A6041E4, 0xB369105E, 0xC46E20C8, 1304 0x72080DF5, 0x050F3D63, 0x9C066CD9, 0xEB015C4F, 1305 0x7565C9EC, 0x0262F97A, 0x9B6BA8C0, 0xEC6C9856, 1306 0x7CD385C7, 0x0BD4B551, 0x92DDE4EB, 0xE5DAD47D, 1307 0x7BBE41DE, 0x0CB97148, 0x95B020F2, 0xE2B71064, 1308 0x6FBF1D91, 0x18B82D07, 0x81B17CBD, 0xF6B64C2B, 1309 0x68D2D988, 0x1FD5E91E, 0x86DCB8A4, 0xF1DB8832, 1310 0x616495A3, 0x1663A535, 0x8F6AF48F, 0xF86DC419, 1311 0x660951BA, 0x110E612C, 0x88073096, 0xFF000000 1312 }; 1313