linux/arch/sparc/kernel/viohs.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/* viohs.c: LDOM Virtual I/O handshake helper layer.
   3 *
   4 * Copyright (C) 2007 David S. Miller <davem@davemloft.net>
   5 */
   6
   7#include <linux/kernel.h>
   8#include <linux/export.h>
   9#include <linux/string.h>
  10#include <linux/delay.h>
  11#include <linux/sched.h>
  12#include <linux/sched/clock.h>
  13#include <linux/slab.h>
  14
  15#include <asm/ldc.h>
  16#include <asm/vio.h>
  17
  18int vio_ldc_send(struct vio_driver_state *vio, void *data, int len)
  19{
  20        int err, limit = 1000;
  21
  22        err = -EINVAL;
  23        while (limit-- > 0) {
  24                err = ldc_write(vio->lp, data, len);
  25                if (!err || (err != -EAGAIN))
  26                        break;
  27                udelay(1);
  28        }
  29
  30        return err;
  31}
  32EXPORT_SYMBOL(vio_ldc_send);
  33
  34static int send_ctrl(struct vio_driver_state *vio,
  35                     struct vio_msg_tag *tag, int len)
  36{
  37        tag->sid = vio_send_sid(vio);
  38        return vio_ldc_send(vio, tag, len);
  39}
  40
  41static void init_tag(struct vio_msg_tag *tag, u8 type, u8 stype, u16 stype_env)
  42{
  43        tag->type = type;
  44        tag->stype = stype;
  45        tag->stype_env = stype_env;
  46}
  47
  48static int send_version(struct vio_driver_state *vio, u16 major, u16 minor)
  49{
  50        struct vio_ver_info pkt;
  51
  52        vio->_local_sid = (u32) sched_clock();
  53
  54        memset(&pkt, 0, sizeof(pkt));
  55        init_tag(&pkt.tag, VIO_TYPE_CTRL, VIO_SUBTYPE_INFO, VIO_VER_INFO);
  56        pkt.major = major;
  57        pkt.minor = minor;
  58        pkt.dev_class = vio->dev_class;
  59
  60        viodbg(HS, "SEND VERSION INFO maj[%u] min[%u] devclass[%u]\n",
  61               major, minor, vio->dev_class);
  62
  63        return send_ctrl(vio, &pkt.tag, sizeof(pkt));
  64}
  65
  66static int start_handshake(struct vio_driver_state *vio)
  67{
  68        int err;
  69
  70        viodbg(HS, "START HANDSHAKE\n");
  71
  72        vio->hs_state = VIO_HS_INVALID;
  73
  74        err = send_version(vio,
  75                           vio->ver_table[0].major,
  76                           vio->ver_table[0].minor);
  77        if (err < 0)
  78                return err;
  79
  80        return 0;
  81}
  82
  83static void flush_rx_dring(struct vio_driver_state *vio)
  84{
  85        struct vio_dring_state *dr;
  86        u64 ident;
  87
  88        BUG_ON(!(vio->dr_state & VIO_DR_STATE_RXREG));
  89
  90        dr = &vio->drings[VIO_DRIVER_RX_RING];
  91        ident = dr->ident;
  92
  93        BUG_ON(!vio->desc_buf);
  94        kfree(vio->desc_buf);
  95        vio->desc_buf = NULL;
  96
  97        memset(dr, 0, sizeof(*dr));
  98        dr->ident = ident;
  99}
 100
 101void vio_link_state_change(struct vio_driver_state *vio, int event)
 102{
 103        if (event == LDC_EVENT_UP) {
 104                vio->hs_state = VIO_HS_INVALID;
 105
 106                switch (vio->dev_class) {
 107                case VDEV_NETWORK:
 108                case VDEV_NETWORK_SWITCH:
 109                        vio->dr_state = (VIO_DR_STATE_TXREQ |
 110                                         VIO_DR_STATE_RXREQ);
 111                        break;
 112
 113                case VDEV_DISK:
 114                        vio->dr_state = VIO_DR_STATE_TXREQ;
 115                        break;
 116                case VDEV_DISK_SERVER:
 117                        vio->dr_state = VIO_DR_STATE_RXREQ;
 118                        break;
 119                }
 120                start_handshake(vio);
 121        } else if (event == LDC_EVENT_RESET) {
 122                vio->hs_state = VIO_HS_INVALID;
 123
 124                if (vio->dr_state & VIO_DR_STATE_RXREG)
 125                        flush_rx_dring(vio);
 126
 127                vio->dr_state = 0x00;
 128                memset(&vio->ver, 0, sizeof(vio->ver));
 129
 130                ldc_disconnect(vio->lp);
 131        }
 132}
 133EXPORT_SYMBOL(vio_link_state_change);
 134
 135static int handshake_failure(struct vio_driver_state *vio)
 136{
 137        struct vio_dring_state *dr;
 138
 139        /* XXX Put policy here...  Perhaps start a timer to fire
 140         * XXX in 100 ms, which will bring the link up and retry
 141         * XXX the handshake.
 142         */
 143
 144        viodbg(HS, "HANDSHAKE FAILURE\n");
 145
 146        vio->dr_state &= ~(VIO_DR_STATE_TXREG |
 147                           VIO_DR_STATE_RXREG);
 148
 149        dr = &vio->drings[VIO_DRIVER_RX_RING];
 150        memset(dr, 0, sizeof(*dr));
 151
 152        kfree(vio->desc_buf);
 153        vio->desc_buf = NULL;
 154        vio->desc_buf_len = 0;
 155
 156        vio->hs_state = VIO_HS_INVALID;
 157
 158        return -ECONNRESET;
 159}
 160
 161static int process_unknown(struct vio_driver_state *vio, void *arg)
 162{
 163        struct vio_msg_tag *pkt = arg;
 164
 165        viodbg(HS, "UNKNOWN CONTROL [%02x:%02x:%04x:%08x]\n",
 166               pkt->type, pkt->stype, pkt->stype_env, pkt->sid);
 167
 168        printk(KERN_ERR "vio: ID[%lu] Resetting connection.\n",
 169               vio->vdev->channel_id);
 170
 171        ldc_disconnect(vio->lp);
 172
 173        return -ECONNRESET;
 174}
 175
 176static int send_dreg(struct vio_driver_state *vio)
 177{
 178        struct vio_dring_state *dr = &vio->drings[VIO_DRIVER_TX_RING];
 179        union {
 180                struct vio_dring_register pkt;
 181                char all[sizeof(struct vio_dring_register) +
 182                         (sizeof(struct ldc_trans_cookie) *
 183                          VIO_MAX_RING_COOKIES)];
 184        } u;
 185        size_t bytes = sizeof(struct vio_dring_register) +
 186                       (sizeof(struct ldc_trans_cookie) *
 187                        dr->ncookies);
 188        int i;
 189
 190        if (WARN_ON(bytes > sizeof(u)))
 191                return -EINVAL;
 192
 193        memset(&u, 0, bytes);
 194        init_tag(&u.pkt.tag, VIO_TYPE_CTRL, VIO_SUBTYPE_INFO, VIO_DRING_REG);
 195        u.pkt.dring_ident = 0;
 196        u.pkt.num_descr = dr->num_entries;
 197        u.pkt.descr_size = dr->entry_size;
 198        u.pkt.options = VIO_TX_DRING;
 199        u.pkt.num_cookies = dr->ncookies;
 200
 201        viodbg(HS, "SEND DRING_REG INFO ndesc[%u] dsz[%u] opt[0x%x] "
 202               "ncookies[%u]\n",
 203               u.pkt.num_descr, u.pkt.descr_size, u.pkt.options,
 204               u.pkt.num_cookies);
 205
 206        for (i = 0; i < dr->ncookies; i++) {
 207                u.pkt.cookies[i] = dr->cookies[i];
 208
 209                viodbg(HS, "DRING COOKIE(%d) [%016llx:%016llx]\n",
 210                       i,
 211                       (unsigned long long) u.pkt.cookies[i].cookie_addr,
 212                       (unsigned long long) u.pkt.cookies[i].cookie_size);
 213        }
 214
 215        return send_ctrl(vio, &u.pkt.tag, bytes);
 216}
 217
 218static int send_rdx(struct vio_driver_state *vio)
 219{
 220        struct vio_rdx pkt;
 221
 222        memset(&pkt, 0, sizeof(pkt));
 223
 224        init_tag(&pkt.tag, VIO_TYPE_CTRL, VIO_SUBTYPE_INFO, VIO_RDX);
 225
 226        viodbg(HS, "SEND RDX INFO\n");
 227
 228        return send_ctrl(vio, &pkt.tag, sizeof(pkt));
 229}
 230
 231static int send_attr(struct vio_driver_state *vio)
 232{
 233        if (!vio->ops)
 234                return -EINVAL;
 235
 236        return vio->ops->send_attr(vio);
 237}
 238
 239static struct vio_version *find_by_major(struct vio_driver_state *vio,
 240                                         u16 major)
 241{
 242        struct vio_version *ret = NULL;
 243        int i;
 244
 245        for (i = 0; i < vio->ver_table_entries; i++) {
 246                struct vio_version *v = &vio->ver_table[i];
 247                if (v->major <= major) {
 248                        ret = v;
 249                        break;
 250                }
 251        }
 252        return ret;
 253}
 254
 255static int process_ver_info(struct vio_driver_state *vio,
 256                            struct vio_ver_info *pkt)
 257{
 258        struct vio_version *vap;
 259        int err;
 260
 261        viodbg(HS, "GOT VERSION INFO maj[%u] min[%u] devclass[%u]\n",
 262               pkt->major, pkt->minor, pkt->dev_class);
 263
 264        if (vio->hs_state != VIO_HS_INVALID) {
 265                /* XXX Perhaps invoke start_handshake? XXX */
 266                memset(&vio->ver, 0, sizeof(vio->ver));
 267                vio->hs_state = VIO_HS_INVALID;
 268        }
 269
 270        vap = find_by_major(vio, pkt->major);
 271
 272        vio->_peer_sid = pkt->tag.sid;
 273
 274        if (!vap) {
 275                pkt->tag.stype = VIO_SUBTYPE_NACK;
 276                pkt->major = 0;
 277                pkt->minor = 0;
 278                viodbg(HS, "SEND VERSION NACK maj[0] min[0]\n");
 279                err = send_ctrl(vio, &pkt->tag, sizeof(*pkt));
 280        } else if (vap->major != pkt->major) {
 281                pkt->tag.stype = VIO_SUBTYPE_NACK;
 282                pkt->major = vap->major;
 283                pkt->minor = vap->minor;
 284                viodbg(HS, "SEND VERSION NACK maj[%u] min[%u]\n",
 285                       pkt->major, pkt->minor);
 286                err = send_ctrl(vio, &pkt->tag, sizeof(*pkt));
 287        } else {
 288                struct vio_version ver = {
 289                        .major = pkt->major,
 290                        .minor = pkt->minor,
 291                };
 292                if (ver.minor > vap->minor)
 293                        ver.minor = vap->minor;
 294                pkt->minor = ver.minor;
 295                pkt->tag.stype = VIO_SUBTYPE_ACK;
 296                pkt->dev_class = vio->dev_class;
 297                viodbg(HS, "SEND VERSION ACK maj[%u] min[%u]\n",
 298                       pkt->major, pkt->minor);
 299                err = send_ctrl(vio, &pkt->tag, sizeof(*pkt));
 300                if (err > 0) {
 301                        vio->ver = ver;
 302                        vio->hs_state = VIO_HS_GOTVERS;
 303                }
 304        }
 305        if (err < 0)
 306                return handshake_failure(vio);
 307
 308        return 0;
 309}
 310
 311static int process_ver_ack(struct vio_driver_state *vio,
 312                           struct vio_ver_info *pkt)
 313{
 314        viodbg(HS, "GOT VERSION ACK maj[%u] min[%u] devclass[%u]\n",
 315               pkt->major, pkt->minor, pkt->dev_class);
 316
 317        if (vio->hs_state & VIO_HS_GOTVERS) {
 318                if (vio->ver.major != pkt->major ||
 319                    vio->ver.minor != pkt->minor) {
 320                        pkt->tag.stype = VIO_SUBTYPE_NACK;
 321                        (void) send_ctrl(vio, &pkt->tag, sizeof(*pkt));
 322                        return handshake_failure(vio);
 323                }
 324        } else {
 325                vio->ver.major = pkt->major;
 326                vio->ver.minor = pkt->minor;
 327                vio->hs_state = VIO_HS_GOTVERS;
 328        }
 329
 330        switch (vio->dev_class) {
 331        case VDEV_NETWORK:
 332        case VDEV_DISK:
 333                if (send_attr(vio) < 0)
 334                        return handshake_failure(vio);
 335                break;
 336
 337        default:
 338                break;
 339        }
 340
 341        return 0;
 342}
 343
 344static int process_ver_nack(struct vio_driver_state *vio,
 345                            struct vio_ver_info *pkt)
 346{
 347        struct vio_version *nver;
 348
 349        viodbg(HS, "GOT VERSION NACK maj[%u] min[%u] devclass[%u]\n",
 350               pkt->major, pkt->minor, pkt->dev_class);
 351
 352        if (pkt->major == 0 && pkt->minor == 0)
 353                return handshake_failure(vio);
 354        nver = find_by_major(vio, pkt->major);
 355        if (!nver)
 356                return handshake_failure(vio);
 357
 358        if (send_version(vio, nver->major, nver->minor) < 0)
 359                return handshake_failure(vio);
 360
 361        return 0;
 362}
 363
 364static int process_ver(struct vio_driver_state *vio, struct vio_ver_info *pkt)
 365{
 366        switch (pkt->tag.stype) {
 367        case VIO_SUBTYPE_INFO:
 368                return process_ver_info(vio, pkt);
 369
 370        case VIO_SUBTYPE_ACK:
 371                return process_ver_ack(vio, pkt);
 372
 373        case VIO_SUBTYPE_NACK:
 374                return process_ver_nack(vio, pkt);
 375
 376        default:
 377                return handshake_failure(vio);
 378        }
 379}
 380
 381static int process_attr(struct vio_driver_state *vio, void *pkt)
 382{
 383        int err;
 384
 385        if (!(vio->hs_state & VIO_HS_GOTVERS))
 386                return handshake_failure(vio);
 387
 388        if (!vio->ops)
 389                return 0;
 390
 391        err = vio->ops->handle_attr(vio, pkt);
 392        if (err < 0) {
 393                return handshake_failure(vio);
 394        } else {
 395                vio->hs_state |= VIO_HS_GOT_ATTR;
 396
 397                if ((vio->dr_state & VIO_DR_STATE_TXREQ) &&
 398                    !(vio->hs_state & VIO_HS_SENT_DREG)) {
 399                        if (send_dreg(vio) < 0)
 400                                return handshake_failure(vio);
 401
 402                        vio->hs_state |= VIO_HS_SENT_DREG;
 403                }
 404        }
 405
 406        return 0;
 407}
 408
 409static int all_drings_registered(struct vio_driver_state *vio)
 410{
 411        int need_rx, need_tx;
 412
 413        need_rx = (vio->dr_state & VIO_DR_STATE_RXREQ);
 414        need_tx = (vio->dr_state & VIO_DR_STATE_TXREQ);
 415
 416        if (need_rx &&
 417            !(vio->dr_state & VIO_DR_STATE_RXREG))
 418                return 0;
 419
 420        if (need_tx &&
 421            !(vio->dr_state & VIO_DR_STATE_TXREG))
 422                return 0;
 423
 424        return 1;
 425}
 426
 427static int process_dreg_info(struct vio_driver_state *vio,
 428                             struct vio_dring_register *pkt)
 429{
 430        struct vio_dring_state *dr;
 431        int i, len;
 432
 433        viodbg(HS, "GOT DRING_REG INFO ident[%llx] "
 434               "ndesc[%u] dsz[%u] opt[0x%x] ncookies[%u]\n",
 435               (unsigned long long) pkt->dring_ident,
 436               pkt->num_descr, pkt->descr_size, pkt->options,
 437               pkt->num_cookies);
 438
 439        if (!(vio->dr_state & VIO_DR_STATE_RXREQ))
 440                goto send_nack;
 441
 442        if (vio->dr_state & VIO_DR_STATE_RXREG)
 443                goto send_nack;
 444
 445        /* v1.6 and higher, ACK with desired, supported mode, or NACK */
 446        if (vio_version_after_eq(vio, 1, 6)) {
 447                if (!(pkt->options & VIO_TX_DRING))
 448                        goto send_nack;
 449                pkt->options = VIO_TX_DRING;
 450        }
 451
 452        BUG_ON(vio->desc_buf);
 453
 454        vio->desc_buf = kzalloc(pkt->descr_size, GFP_ATOMIC);
 455        if (!vio->desc_buf)
 456                goto send_nack;
 457
 458        vio->desc_buf_len = pkt->descr_size;
 459
 460        dr = &vio->drings[VIO_DRIVER_RX_RING];
 461
 462        dr->num_entries = pkt->num_descr;
 463        dr->entry_size = pkt->descr_size;
 464        dr->ncookies = pkt->num_cookies;
 465        for (i = 0; i < dr->ncookies; i++) {
 466                dr->cookies[i] = pkt->cookies[i];
 467
 468                viodbg(HS, "DRING COOKIE(%d) [%016llx:%016llx]\n",
 469                       i,
 470                       (unsigned long long)
 471                       pkt->cookies[i].cookie_addr,
 472                       (unsigned long long)
 473                       pkt->cookies[i].cookie_size);
 474        }
 475
 476        pkt->tag.stype = VIO_SUBTYPE_ACK;
 477        pkt->dring_ident = ++dr->ident;
 478
 479        viodbg(HS, "SEND DRING_REG ACK ident[%llx] "
 480               "ndesc[%u] dsz[%u] opt[0x%x] ncookies[%u]\n",
 481               (unsigned long long) pkt->dring_ident,
 482               pkt->num_descr, pkt->descr_size, pkt->options,
 483               pkt->num_cookies);
 484
 485        len = (sizeof(*pkt) +
 486               (dr->ncookies * sizeof(struct ldc_trans_cookie)));
 487        if (send_ctrl(vio, &pkt->tag, len) < 0)
 488                goto send_nack;
 489
 490        vio->dr_state |= VIO_DR_STATE_RXREG;
 491
 492        return 0;
 493
 494send_nack:
 495        pkt->tag.stype = VIO_SUBTYPE_NACK;
 496        viodbg(HS, "SEND DRING_REG NACK\n");
 497        (void) send_ctrl(vio, &pkt->tag, sizeof(*pkt));
 498
 499        return handshake_failure(vio);
 500}
 501
 502static int process_dreg_ack(struct vio_driver_state *vio,
 503                            struct vio_dring_register *pkt)
 504{
 505        struct vio_dring_state *dr;
 506
 507        viodbg(HS, "GOT DRING_REG ACK ident[%llx] "
 508               "ndesc[%u] dsz[%u] opt[0x%x] ncookies[%u]\n",
 509               (unsigned long long) pkt->dring_ident,
 510               pkt->num_descr, pkt->descr_size, pkt->options,
 511               pkt->num_cookies);
 512
 513        dr = &vio->drings[VIO_DRIVER_TX_RING];
 514
 515        if (!(vio->dr_state & VIO_DR_STATE_TXREQ))
 516                return handshake_failure(vio);
 517
 518        dr->ident = pkt->dring_ident;
 519        vio->dr_state |= VIO_DR_STATE_TXREG;
 520
 521        if (all_drings_registered(vio)) {
 522                if (send_rdx(vio) < 0)
 523                        return handshake_failure(vio);
 524                vio->hs_state = VIO_HS_SENT_RDX;
 525        }
 526        return 0;
 527}
 528
 529static int process_dreg_nack(struct vio_driver_state *vio,
 530                             struct vio_dring_register *pkt)
 531{
 532        viodbg(HS, "GOT DRING_REG NACK ident[%llx] "
 533               "ndesc[%u] dsz[%u] opt[0x%x] ncookies[%u]\n",
 534               (unsigned long long) pkt->dring_ident,
 535               pkt->num_descr, pkt->descr_size, pkt->options,
 536               pkt->num_cookies);
 537
 538        return handshake_failure(vio);
 539}
 540
 541static int process_dreg(struct vio_driver_state *vio,
 542                        struct vio_dring_register *pkt)
 543{
 544        if (!(vio->hs_state & VIO_HS_GOTVERS))
 545                return handshake_failure(vio);
 546
 547        switch (pkt->tag.stype) {
 548        case VIO_SUBTYPE_INFO:
 549                return process_dreg_info(vio, pkt);
 550
 551        case VIO_SUBTYPE_ACK:
 552                return process_dreg_ack(vio, pkt);
 553
 554        case VIO_SUBTYPE_NACK:
 555                return process_dreg_nack(vio, pkt);
 556
 557        default:
 558                return handshake_failure(vio);
 559        }
 560}
 561
 562static int process_dunreg(struct vio_driver_state *vio,
 563                          struct vio_dring_unregister *pkt)
 564{
 565        struct vio_dring_state *dr = &vio->drings[VIO_DRIVER_RX_RING];
 566
 567        viodbg(HS, "GOT DRING_UNREG\n");
 568
 569        if (pkt->dring_ident != dr->ident)
 570                return 0;
 571
 572        vio->dr_state &= ~VIO_DR_STATE_RXREG;
 573
 574        memset(dr, 0, sizeof(*dr));
 575
 576        kfree(vio->desc_buf);
 577        vio->desc_buf = NULL;
 578        vio->desc_buf_len = 0;
 579
 580        return 0;
 581}
 582
 583static int process_rdx_info(struct vio_driver_state *vio, struct vio_rdx *pkt)
 584{
 585        viodbg(HS, "GOT RDX INFO\n");
 586
 587        pkt->tag.stype = VIO_SUBTYPE_ACK;
 588        viodbg(HS, "SEND RDX ACK\n");
 589        if (send_ctrl(vio, &pkt->tag, sizeof(*pkt)) < 0)
 590                return handshake_failure(vio);
 591
 592        vio->hs_state |= VIO_HS_SENT_RDX_ACK;
 593        return 0;
 594}
 595
 596static int process_rdx_ack(struct vio_driver_state *vio, struct vio_rdx *pkt)
 597{
 598        viodbg(HS, "GOT RDX ACK\n");
 599
 600        if (!(vio->hs_state & VIO_HS_SENT_RDX))
 601                return handshake_failure(vio);
 602
 603        vio->hs_state |= VIO_HS_GOT_RDX_ACK;
 604        return 0;
 605}
 606
 607static int process_rdx_nack(struct vio_driver_state *vio, struct vio_rdx *pkt)
 608{
 609        viodbg(HS, "GOT RDX NACK\n");
 610
 611        return handshake_failure(vio);
 612}
 613
 614static int process_rdx(struct vio_driver_state *vio, struct vio_rdx *pkt)
 615{
 616        if (!all_drings_registered(vio))
 617                handshake_failure(vio);
 618
 619        switch (pkt->tag.stype) {
 620        case VIO_SUBTYPE_INFO:
 621                return process_rdx_info(vio, pkt);
 622
 623        case VIO_SUBTYPE_ACK:
 624                return process_rdx_ack(vio, pkt);
 625
 626        case VIO_SUBTYPE_NACK:
 627                return process_rdx_nack(vio, pkt);
 628
 629        default:
 630                return handshake_failure(vio);
 631        }
 632}
 633
 634int vio_control_pkt_engine(struct vio_driver_state *vio, void *pkt)
 635{
 636        struct vio_msg_tag *tag = pkt;
 637        u8 prev_state = vio->hs_state;
 638        int err;
 639
 640        switch (tag->stype_env) {
 641        case VIO_VER_INFO:
 642                err = process_ver(vio, pkt);
 643                break;
 644
 645        case VIO_ATTR_INFO:
 646                err = process_attr(vio, pkt);
 647                break;
 648
 649        case VIO_DRING_REG:
 650                err = process_dreg(vio, pkt);
 651                break;
 652
 653        case VIO_DRING_UNREG:
 654                err = process_dunreg(vio, pkt);
 655                break;
 656
 657        case VIO_RDX:
 658                err = process_rdx(vio, pkt);
 659                break;
 660
 661        default:
 662                err = process_unknown(vio, pkt);
 663                break;
 664        }
 665
 666        if (!err &&
 667            vio->hs_state != prev_state &&
 668            (vio->hs_state & VIO_HS_COMPLETE)) {
 669                if (vio->ops)
 670                        vio->ops->handshake_complete(vio);
 671        }
 672
 673        return err;
 674}
 675EXPORT_SYMBOL(vio_control_pkt_engine);
 676
 677void vio_conn_reset(struct vio_driver_state *vio)
 678{
 679}
 680EXPORT_SYMBOL(vio_conn_reset);
 681
 682/* The issue is that the Solaris virtual disk server just mirrors the
 683 * SID values it gets from the client peer.  So we work around that
 684 * here in vio_{validate,send}_sid() so that the drivers don't need
 685 * to be aware of this crap.
 686 */
 687int vio_validate_sid(struct vio_driver_state *vio, struct vio_msg_tag *tp)
 688{
 689        u32 sid;
 690
 691        /* Always let VERSION+INFO packets through unchecked, they
 692         * define the new SID.
 693         */
 694        if (tp->type == VIO_TYPE_CTRL &&
 695            tp->stype == VIO_SUBTYPE_INFO &&
 696            tp->stype_env == VIO_VER_INFO)
 697                return 0;
 698
 699        /* Ok, now figure out which SID to use.  */
 700        switch (vio->dev_class) {
 701        case VDEV_NETWORK:
 702        case VDEV_NETWORK_SWITCH:
 703        case VDEV_DISK_SERVER:
 704        default:
 705                sid = vio->_peer_sid;
 706                break;
 707
 708        case VDEV_DISK:
 709                sid = vio->_local_sid;
 710                break;
 711        }
 712
 713        if (sid == tp->sid)
 714                return 0;
 715        viodbg(DATA, "BAD SID tag->sid[%08x] peer_sid[%08x] local_sid[%08x]\n",
 716               tp->sid, vio->_peer_sid, vio->_local_sid);
 717        return -EINVAL;
 718}
 719EXPORT_SYMBOL(vio_validate_sid);
 720
 721u32 vio_send_sid(struct vio_driver_state *vio)
 722{
 723        switch (vio->dev_class) {
 724        case VDEV_NETWORK:
 725        case VDEV_NETWORK_SWITCH:
 726        case VDEV_DISK:
 727        default:
 728                return vio->_local_sid;
 729
 730        case VDEV_DISK_SERVER:
 731                return vio->_peer_sid;
 732        }
 733}
 734EXPORT_SYMBOL(vio_send_sid);
 735
 736int vio_ldc_alloc(struct vio_driver_state *vio,
 737                         struct ldc_channel_config *base_cfg,
 738                         void *event_arg)
 739{
 740        struct ldc_channel_config cfg = *base_cfg;
 741        struct ldc_channel *lp;
 742
 743        cfg.tx_irq = vio->vdev->tx_irq;
 744        cfg.rx_irq = vio->vdev->rx_irq;
 745
 746        lp = ldc_alloc(vio->vdev->channel_id, &cfg, event_arg, vio->name);
 747        if (IS_ERR(lp))
 748                return PTR_ERR(lp);
 749
 750        vio->lp = lp;
 751
 752        return 0;
 753}
 754EXPORT_SYMBOL(vio_ldc_alloc);
 755
 756void vio_ldc_free(struct vio_driver_state *vio)
 757{
 758        ldc_free(vio->lp);
 759        vio->lp = NULL;
 760
 761        kfree(vio->desc_buf);
 762        vio->desc_buf = NULL;
 763        vio->desc_buf_len = 0;
 764}
 765EXPORT_SYMBOL(vio_ldc_free);
 766
 767void vio_port_up(struct vio_driver_state *vio)
 768{
 769        unsigned long flags;
 770        int err, state;
 771
 772        spin_lock_irqsave(&vio->lock, flags);
 773
 774        state = ldc_state(vio->lp);
 775
 776        err = 0;
 777        if (state == LDC_STATE_INIT) {
 778                err = ldc_bind(vio->lp);
 779                if (err)
 780                        printk(KERN_WARNING "%s: Port %lu bind failed, "
 781                               "err=%d\n",
 782                               vio->name, vio->vdev->channel_id, err);
 783        }
 784
 785        if (!err) {
 786                if (ldc_mode(vio->lp) == LDC_MODE_RAW)
 787                        ldc_set_state(vio->lp, LDC_STATE_CONNECTED);
 788                else
 789                        err = ldc_connect(vio->lp);
 790
 791                if (err)
 792                        printk(KERN_WARNING "%s: Port %lu connect failed, "
 793                               "err=%d\n",
 794                               vio->name, vio->vdev->channel_id, err);
 795        }
 796        if (err) {
 797                unsigned long expires = jiffies + HZ;
 798
 799                expires = round_jiffies(expires);
 800                mod_timer(&vio->timer, expires);
 801        }
 802
 803        spin_unlock_irqrestore(&vio->lock, flags);
 804}
 805EXPORT_SYMBOL(vio_port_up);
 806
 807static void vio_port_timer(struct timer_list *t)
 808{
 809        struct vio_driver_state *vio = from_timer(vio, t, timer);
 810
 811        vio_port_up(vio);
 812}
 813
 814int vio_driver_init(struct vio_driver_state *vio, struct vio_dev *vdev,
 815                    u8 dev_class, struct vio_version *ver_table,
 816                    int ver_table_size, struct vio_driver_ops *ops,
 817                    char *name)
 818{
 819        switch (dev_class) {
 820        case VDEV_NETWORK:
 821        case VDEV_NETWORK_SWITCH:
 822        case VDEV_DISK:
 823        case VDEV_DISK_SERVER:
 824        case VDEV_CONSOLE_CON:
 825                break;
 826
 827        default:
 828                return -EINVAL;
 829        }
 830
 831        if (dev_class == VDEV_NETWORK ||
 832            dev_class == VDEV_NETWORK_SWITCH ||
 833            dev_class == VDEV_DISK ||
 834            dev_class == VDEV_DISK_SERVER) {
 835                if (!ops || !ops->send_attr || !ops->handle_attr ||
 836                    !ops->handshake_complete)
 837                        return -EINVAL;
 838        }
 839
 840        if (!ver_table || ver_table_size < 0)
 841                return -EINVAL;
 842
 843        if (!name)
 844                return -EINVAL;
 845
 846        spin_lock_init(&vio->lock);
 847
 848        vio->name = name;
 849
 850        vio->dev_class = dev_class;
 851        vio->vdev = vdev;
 852
 853        vio->ver_table = ver_table;
 854        vio->ver_table_entries = ver_table_size;
 855
 856        vio->ops = ops;
 857
 858        timer_setup(&vio->timer, vio_port_timer, 0);
 859
 860        return 0;
 861}
 862EXPORT_SYMBOL(vio_driver_init);
 863