Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /* viohs.c: LDOM Virtual I/O handshake helper layer.
0003  *
0004  * Copyright (C) 2007 David S. Miller <davem@davemloft.net>
0005  */
0006 
0007 #include <linux/kernel.h>
0008 #include <linux/export.h>
0009 #include <linux/string.h>
0010 #include <linux/delay.h>
0011 #include <linux/sched.h>
0012 #include <linux/sched/clock.h>
0013 #include <linux/slab.h>
0014 
0015 #include <asm/ldc.h>
0016 #include <asm/vio.h>
0017 
0018 int vio_ldc_send(struct vio_driver_state *vio, void *data, int len)
0019 {
0020     int err, limit = 1000;
0021 
0022     err = -EINVAL;
0023     while (limit-- > 0) {
0024         err = ldc_write(vio->lp, data, len);
0025         if (!err || (err != -EAGAIN))
0026             break;
0027         udelay(1);
0028     }
0029 
0030     return err;
0031 }
0032 EXPORT_SYMBOL(vio_ldc_send);
0033 
0034 static int send_ctrl(struct vio_driver_state *vio,
0035              struct vio_msg_tag *tag, int len)
0036 {
0037     tag->sid = vio_send_sid(vio);
0038     return vio_ldc_send(vio, tag, len);
0039 }
0040 
0041 static void init_tag(struct vio_msg_tag *tag, u8 type, u8 stype, u16 stype_env)
0042 {
0043     tag->type = type;
0044     tag->stype = stype;
0045     tag->stype_env = stype_env;
0046 }
0047 
0048 static int send_version(struct vio_driver_state *vio, u16 major, u16 minor)
0049 {
0050     struct vio_ver_info pkt;
0051 
0052     vio->_local_sid = (u32) sched_clock();
0053 
0054     memset(&pkt, 0, sizeof(pkt));
0055     init_tag(&pkt.tag, VIO_TYPE_CTRL, VIO_SUBTYPE_INFO, VIO_VER_INFO);
0056     pkt.major = major;
0057     pkt.minor = minor;
0058     pkt.dev_class = vio->dev_class;
0059 
0060     viodbg(HS, "SEND VERSION INFO maj[%u] min[%u] devclass[%u]\n",
0061            major, minor, vio->dev_class);
0062 
0063     return send_ctrl(vio, &pkt.tag, sizeof(pkt));
0064 }
0065 
0066 static int start_handshake(struct vio_driver_state *vio)
0067 {
0068     int err;
0069 
0070     viodbg(HS, "START HANDSHAKE\n");
0071 
0072     vio->hs_state = VIO_HS_INVALID;
0073 
0074     err = send_version(vio,
0075                vio->ver_table[0].major,
0076                vio->ver_table[0].minor);
0077     if (err < 0)
0078         return err;
0079 
0080     return 0;
0081 }
0082 
0083 static void flush_rx_dring(struct vio_driver_state *vio)
0084 {
0085     struct vio_dring_state *dr;
0086     u64 ident;
0087 
0088     BUG_ON(!(vio->dr_state & VIO_DR_STATE_RXREG));
0089 
0090     dr = &vio->drings[VIO_DRIVER_RX_RING];
0091     ident = dr->ident;
0092 
0093     BUG_ON(!vio->desc_buf);
0094     kfree(vio->desc_buf);
0095     vio->desc_buf = NULL;
0096 
0097     memset(dr, 0, sizeof(*dr));
0098     dr->ident = ident;
0099 }
0100 
0101 void vio_link_state_change(struct vio_driver_state *vio, int event)
0102 {
0103     if (event == LDC_EVENT_UP) {
0104         vio->hs_state = VIO_HS_INVALID;
0105 
0106         switch (vio->dev_class) {
0107         case VDEV_NETWORK:
0108         case VDEV_NETWORK_SWITCH:
0109             vio->dr_state = (VIO_DR_STATE_TXREQ |
0110                      VIO_DR_STATE_RXREQ);
0111             break;
0112 
0113         case VDEV_DISK:
0114             vio->dr_state = VIO_DR_STATE_TXREQ;
0115             break;
0116         case VDEV_DISK_SERVER:
0117             vio->dr_state = VIO_DR_STATE_RXREQ;
0118             break;
0119         }
0120         start_handshake(vio);
0121     } else if (event == LDC_EVENT_RESET) {
0122         vio->hs_state = VIO_HS_INVALID;
0123 
0124         if (vio->dr_state & VIO_DR_STATE_RXREG)
0125             flush_rx_dring(vio);
0126 
0127         vio->dr_state = 0x00;
0128         memset(&vio->ver, 0, sizeof(vio->ver));
0129 
0130         ldc_disconnect(vio->lp);
0131     }
0132 }
0133 EXPORT_SYMBOL(vio_link_state_change);
0134 
0135 static int handshake_failure(struct vio_driver_state *vio)
0136 {
0137     struct vio_dring_state *dr;
0138 
0139     /* XXX Put policy here...  Perhaps start a timer to fire
0140      * XXX in 100 ms, which will bring the link up and retry
0141      * XXX the handshake.
0142      */
0143 
0144     viodbg(HS, "HANDSHAKE FAILURE\n");
0145 
0146     vio->dr_state &= ~(VIO_DR_STATE_TXREG |
0147                VIO_DR_STATE_RXREG);
0148 
0149     dr = &vio->drings[VIO_DRIVER_RX_RING];
0150     memset(dr, 0, sizeof(*dr));
0151 
0152     kfree(vio->desc_buf);
0153     vio->desc_buf = NULL;
0154     vio->desc_buf_len = 0;
0155 
0156     vio->hs_state = VIO_HS_INVALID;
0157 
0158     return -ECONNRESET;
0159 }
0160 
0161 static int process_unknown(struct vio_driver_state *vio, void *arg)
0162 {
0163     struct vio_msg_tag *pkt = arg;
0164 
0165     viodbg(HS, "UNKNOWN CONTROL [%02x:%02x:%04x:%08x]\n",
0166            pkt->type, pkt->stype, pkt->stype_env, pkt->sid);
0167 
0168     printk(KERN_ERR "vio: ID[%lu] Resetting connection.\n",
0169            vio->vdev->channel_id);
0170 
0171     ldc_disconnect(vio->lp);
0172 
0173     return -ECONNRESET;
0174 }
0175 
0176 static int send_dreg(struct vio_driver_state *vio)
0177 {
0178     struct vio_dring_state *dr = &vio->drings[VIO_DRIVER_TX_RING];
0179     union {
0180         struct vio_dring_register pkt;
0181         char all[sizeof(struct vio_dring_register) +
0182              (sizeof(struct ldc_trans_cookie) *
0183               VIO_MAX_RING_COOKIES)];
0184     } u;
0185     size_t bytes = sizeof(struct vio_dring_register) +
0186                (sizeof(struct ldc_trans_cookie) *
0187             dr->ncookies);
0188     int i;
0189 
0190     if (WARN_ON(bytes > sizeof(u)))
0191         return -EINVAL;
0192 
0193     memset(&u, 0, bytes);
0194     init_tag(&u.pkt.tag, VIO_TYPE_CTRL, VIO_SUBTYPE_INFO, VIO_DRING_REG);
0195     u.pkt.dring_ident = 0;
0196     u.pkt.num_descr = dr->num_entries;
0197     u.pkt.descr_size = dr->entry_size;
0198     u.pkt.options = VIO_TX_DRING;
0199     u.pkt.num_cookies = dr->ncookies;
0200 
0201     viodbg(HS, "SEND DRING_REG INFO ndesc[%u] dsz[%u] opt[0x%x] "
0202            "ncookies[%u]\n",
0203            u.pkt.num_descr, u.pkt.descr_size, u.pkt.options,
0204            u.pkt.num_cookies);
0205 
0206     for (i = 0; i < dr->ncookies; i++) {
0207         u.pkt.cookies[i] = dr->cookies[i];
0208 
0209         viodbg(HS, "DRING COOKIE(%d) [%016llx:%016llx]\n",
0210                i,
0211                (unsigned long long) u.pkt.cookies[i].cookie_addr,
0212                (unsigned long long) u.pkt.cookies[i].cookie_size);
0213     }
0214 
0215     return send_ctrl(vio, &u.pkt.tag, bytes);
0216 }
0217 
0218 static int send_rdx(struct vio_driver_state *vio)
0219 {
0220     struct vio_rdx pkt;
0221 
0222     memset(&pkt, 0, sizeof(pkt));
0223 
0224     init_tag(&pkt.tag, VIO_TYPE_CTRL, VIO_SUBTYPE_INFO, VIO_RDX);
0225 
0226     viodbg(HS, "SEND RDX INFO\n");
0227 
0228     return send_ctrl(vio, &pkt.tag, sizeof(pkt));
0229 }
0230 
0231 static int send_attr(struct vio_driver_state *vio)
0232 {
0233     if (!vio->ops)
0234         return -EINVAL;
0235 
0236     return vio->ops->send_attr(vio);
0237 }
0238 
0239 static struct vio_version *find_by_major(struct vio_driver_state *vio,
0240                      u16 major)
0241 {
0242     struct vio_version *ret = NULL;
0243     int i;
0244 
0245     for (i = 0; i < vio->ver_table_entries; i++) {
0246         struct vio_version *v = &vio->ver_table[i];
0247         if (v->major <= major) {
0248             ret = v;
0249             break;
0250         }
0251     }
0252     return ret;
0253 }
0254 
0255 static int process_ver_info(struct vio_driver_state *vio,
0256                 struct vio_ver_info *pkt)
0257 {
0258     struct vio_version *vap;
0259     int err;
0260 
0261     viodbg(HS, "GOT VERSION INFO maj[%u] min[%u] devclass[%u]\n",
0262            pkt->major, pkt->minor, pkt->dev_class);
0263 
0264     if (vio->hs_state != VIO_HS_INVALID) {
0265         /* XXX Perhaps invoke start_handshake? XXX */
0266         memset(&vio->ver, 0, sizeof(vio->ver));
0267         vio->hs_state = VIO_HS_INVALID;
0268     }
0269 
0270     vap = find_by_major(vio, pkt->major);
0271 
0272     vio->_peer_sid = pkt->tag.sid;
0273 
0274     if (!vap) {
0275         pkt->tag.stype = VIO_SUBTYPE_NACK;
0276         pkt->major = 0;
0277         pkt->minor = 0;
0278         viodbg(HS, "SEND VERSION NACK maj[0] min[0]\n");
0279         err = send_ctrl(vio, &pkt->tag, sizeof(*pkt));
0280     } else if (vap->major != pkt->major) {
0281         pkt->tag.stype = VIO_SUBTYPE_NACK;
0282         pkt->major = vap->major;
0283         pkt->minor = vap->minor;
0284         viodbg(HS, "SEND VERSION NACK maj[%u] min[%u]\n",
0285                pkt->major, pkt->minor);
0286         err = send_ctrl(vio, &pkt->tag, sizeof(*pkt));
0287     } else {
0288         struct vio_version ver = {
0289             .major = pkt->major,
0290             .minor = pkt->minor,
0291         };
0292         if (ver.minor > vap->minor)
0293             ver.minor = vap->minor;
0294         pkt->minor = ver.minor;
0295         pkt->tag.stype = VIO_SUBTYPE_ACK;
0296         pkt->dev_class = vio->dev_class;
0297         viodbg(HS, "SEND VERSION ACK maj[%u] min[%u]\n",
0298                pkt->major, pkt->minor);
0299         err = send_ctrl(vio, &pkt->tag, sizeof(*pkt));
0300         if (err > 0) {
0301             vio->ver = ver;
0302             vio->hs_state = VIO_HS_GOTVERS;
0303         }
0304     }
0305     if (err < 0)
0306         return handshake_failure(vio);
0307 
0308     return 0;
0309 }
0310 
0311 static int process_ver_ack(struct vio_driver_state *vio,
0312                struct vio_ver_info *pkt)
0313 {
0314     viodbg(HS, "GOT VERSION ACK maj[%u] min[%u] devclass[%u]\n",
0315            pkt->major, pkt->minor, pkt->dev_class);
0316 
0317     if (vio->hs_state & VIO_HS_GOTVERS) {
0318         if (vio->ver.major != pkt->major ||
0319             vio->ver.minor != pkt->minor) {
0320             pkt->tag.stype = VIO_SUBTYPE_NACK;
0321             (void) send_ctrl(vio, &pkt->tag, sizeof(*pkt));
0322             return handshake_failure(vio);
0323         }
0324     } else {
0325         vio->ver.major = pkt->major;
0326         vio->ver.minor = pkt->minor;
0327         vio->hs_state = VIO_HS_GOTVERS;
0328     }
0329 
0330     switch (vio->dev_class) {
0331     case VDEV_NETWORK:
0332     case VDEV_DISK:
0333         if (send_attr(vio) < 0)
0334             return handshake_failure(vio);
0335         break;
0336 
0337     default:
0338         break;
0339     }
0340 
0341     return 0;
0342 }
0343 
0344 static int process_ver_nack(struct vio_driver_state *vio,
0345                 struct vio_ver_info *pkt)
0346 {
0347     struct vio_version *nver;
0348 
0349     viodbg(HS, "GOT VERSION NACK maj[%u] min[%u] devclass[%u]\n",
0350            pkt->major, pkt->minor, pkt->dev_class);
0351 
0352     if (pkt->major == 0 && pkt->minor == 0)
0353         return handshake_failure(vio);
0354     nver = find_by_major(vio, pkt->major);
0355     if (!nver)
0356         return handshake_failure(vio);
0357 
0358     if (send_version(vio, nver->major, nver->minor) < 0)
0359         return handshake_failure(vio);
0360 
0361     return 0;
0362 }
0363 
0364 static int process_ver(struct vio_driver_state *vio, struct vio_ver_info *pkt)
0365 {
0366     switch (pkt->tag.stype) {
0367     case VIO_SUBTYPE_INFO:
0368         return process_ver_info(vio, pkt);
0369 
0370     case VIO_SUBTYPE_ACK:
0371         return process_ver_ack(vio, pkt);
0372 
0373     case VIO_SUBTYPE_NACK:
0374         return process_ver_nack(vio, pkt);
0375 
0376     default:
0377         return handshake_failure(vio);
0378     }
0379 }
0380 
0381 static int process_attr(struct vio_driver_state *vio, void *pkt)
0382 {
0383     int err;
0384 
0385     if (!(vio->hs_state & VIO_HS_GOTVERS))
0386         return handshake_failure(vio);
0387 
0388     if (!vio->ops)
0389         return 0;
0390 
0391     err = vio->ops->handle_attr(vio, pkt);
0392     if (err < 0) {
0393         return handshake_failure(vio);
0394     } else {
0395         vio->hs_state |= VIO_HS_GOT_ATTR;
0396 
0397         if ((vio->dr_state & VIO_DR_STATE_TXREQ) &&
0398             !(vio->hs_state & VIO_HS_SENT_DREG)) {
0399             if (send_dreg(vio) < 0)
0400                 return handshake_failure(vio);
0401 
0402             vio->hs_state |= VIO_HS_SENT_DREG;
0403         }
0404     }
0405 
0406     return 0;
0407 }
0408 
0409 static int all_drings_registered(struct vio_driver_state *vio)
0410 {
0411     int need_rx, need_tx;
0412 
0413     need_rx = (vio->dr_state & VIO_DR_STATE_RXREQ);
0414     need_tx = (vio->dr_state & VIO_DR_STATE_TXREQ);
0415 
0416     if (need_rx &&
0417         !(vio->dr_state & VIO_DR_STATE_RXREG))
0418         return 0;
0419 
0420     if (need_tx &&
0421         !(vio->dr_state & VIO_DR_STATE_TXREG))
0422         return 0;
0423 
0424     return 1;
0425 }
0426 
0427 static int process_dreg_info(struct vio_driver_state *vio,
0428                  struct vio_dring_register *pkt)
0429 {
0430     struct vio_dring_state *dr;
0431     int i;
0432 
0433     viodbg(HS, "GOT DRING_REG INFO ident[%llx] "
0434            "ndesc[%u] dsz[%u] opt[0x%x] ncookies[%u]\n",
0435            (unsigned long long) pkt->dring_ident,
0436            pkt->num_descr, pkt->descr_size, pkt->options,
0437            pkt->num_cookies);
0438 
0439     if (!(vio->dr_state & VIO_DR_STATE_RXREQ))
0440         goto send_nack;
0441 
0442     if (vio->dr_state & VIO_DR_STATE_RXREG)
0443         goto send_nack;
0444 
0445     /* v1.6 and higher, ACK with desired, supported mode, or NACK */
0446     if (vio_version_after_eq(vio, 1, 6)) {
0447         if (!(pkt->options & VIO_TX_DRING))
0448             goto send_nack;
0449         pkt->options = VIO_TX_DRING;
0450     }
0451 
0452     BUG_ON(vio->desc_buf);
0453 
0454     vio->desc_buf = kzalloc(pkt->descr_size, GFP_ATOMIC);
0455     if (!vio->desc_buf)
0456         goto send_nack;
0457 
0458     vio->desc_buf_len = pkt->descr_size;
0459 
0460     dr = &vio->drings[VIO_DRIVER_RX_RING];
0461 
0462     dr->num_entries = pkt->num_descr;
0463     dr->entry_size = pkt->descr_size;
0464     dr->ncookies = pkt->num_cookies;
0465     for (i = 0; i < dr->ncookies; i++) {
0466         dr->cookies[i] = pkt->cookies[i];
0467 
0468         viodbg(HS, "DRING COOKIE(%d) [%016llx:%016llx]\n",
0469                i,
0470                (unsigned long long)
0471                pkt->cookies[i].cookie_addr,
0472                (unsigned long long)
0473                pkt->cookies[i].cookie_size);
0474     }
0475 
0476     pkt->tag.stype = VIO_SUBTYPE_ACK;
0477     pkt->dring_ident = ++dr->ident;
0478 
0479     viodbg(HS, "SEND DRING_REG ACK ident[%llx] "
0480            "ndesc[%u] dsz[%u] opt[0x%x] ncookies[%u]\n",
0481            (unsigned long long) pkt->dring_ident,
0482            pkt->num_descr, pkt->descr_size, pkt->options,
0483            pkt->num_cookies);
0484 
0485     if (send_ctrl(vio, &pkt->tag, struct_size(pkt, cookies, dr->ncookies)) < 0)
0486         goto send_nack;
0487 
0488     vio->dr_state |= VIO_DR_STATE_RXREG;
0489 
0490     return 0;
0491 
0492 send_nack:
0493     pkt->tag.stype = VIO_SUBTYPE_NACK;
0494     viodbg(HS, "SEND DRING_REG NACK\n");
0495     (void) send_ctrl(vio, &pkt->tag, sizeof(*pkt));
0496 
0497     return handshake_failure(vio);
0498 }
0499 
0500 static int process_dreg_ack(struct vio_driver_state *vio,
0501                 struct vio_dring_register *pkt)
0502 {
0503     struct vio_dring_state *dr;
0504 
0505     viodbg(HS, "GOT DRING_REG ACK ident[%llx] "
0506            "ndesc[%u] dsz[%u] opt[0x%x] ncookies[%u]\n",
0507            (unsigned long long) pkt->dring_ident,
0508            pkt->num_descr, pkt->descr_size, pkt->options,
0509            pkt->num_cookies);
0510 
0511     dr = &vio->drings[VIO_DRIVER_TX_RING];
0512 
0513     if (!(vio->dr_state & VIO_DR_STATE_TXREQ))
0514         return handshake_failure(vio);
0515 
0516     dr->ident = pkt->dring_ident;
0517     vio->dr_state |= VIO_DR_STATE_TXREG;
0518 
0519     if (all_drings_registered(vio)) {
0520         if (send_rdx(vio) < 0)
0521             return handshake_failure(vio);
0522         vio->hs_state = VIO_HS_SENT_RDX;
0523     }
0524     return 0;
0525 }
0526 
0527 static int process_dreg_nack(struct vio_driver_state *vio,
0528                  struct vio_dring_register *pkt)
0529 {
0530     viodbg(HS, "GOT DRING_REG NACK ident[%llx] "
0531            "ndesc[%u] dsz[%u] opt[0x%x] ncookies[%u]\n",
0532            (unsigned long long) pkt->dring_ident,
0533            pkt->num_descr, pkt->descr_size, pkt->options,
0534            pkt->num_cookies);
0535 
0536     return handshake_failure(vio);
0537 }
0538 
0539 static int process_dreg(struct vio_driver_state *vio,
0540             struct vio_dring_register *pkt)
0541 {
0542     if (!(vio->hs_state & VIO_HS_GOTVERS))
0543         return handshake_failure(vio);
0544 
0545     switch (pkt->tag.stype) {
0546     case VIO_SUBTYPE_INFO:
0547         return process_dreg_info(vio, pkt);
0548 
0549     case VIO_SUBTYPE_ACK:
0550         return process_dreg_ack(vio, pkt);
0551 
0552     case VIO_SUBTYPE_NACK:
0553         return process_dreg_nack(vio, pkt);
0554 
0555     default:
0556         return handshake_failure(vio);
0557     }
0558 }
0559 
0560 static int process_dunreg(struct vio_driver_state *vio,
0561               struct vio_dring_unregister *pkt)
0562 {
0563     struct vio_dring_state *dr = &vio->drings[VIO_DRIVER_RX_RING];
0564 
0565     viodbg(HS, "GOT DRING_UNREG\n");
0566 
0567     if (pkt->dring_ident != dr->ident)
0568         return 0;
0569 
0570     vio->dr_state &= ~VIO_DR_STATE_RXREG;
0571 
0572     memset(dr, 0, sizeof(*dr));
0573 
0574     kfree(vio->desc_buf);
0575     vio->desc_buf = NULL;
0576     vio->desc_buf_len = 0;
0577 
0578     return 0;
0579 }
0580 
0581 static int process_rdx_info(struct vio_driver_state *vio, struct vio_rdx *pkt)
0582 {
0583     viodbg(HS, "GOT RDX INFO\n");
0584 
0585     pkt->tag.stype = VIO_SUBTYPE_ACK;
0586     viodbg(HS, "SEND RDX ACK\n");
0587     if (send_ctrl(vio, &pkt->tag, sizeof(*pkt)) < 0)
0588         return handshake_failure(vio);
0589 
0590     vio->hs_state |= VIO_HS_SENT_RDX_ACK;
0591     return 0;
0592 }
0593 
0594 static int process_rdx_ack(struct vio_driver_state *vio, struct vio_rdx *pkt)
0595 {
0596     viodbg(HS, "GOT RDX ACK\n");
0597 
0598     if (!(vio->hs_state & VIO_HS_SENT_RDX))
0599         return handshake_failure(vio);
0600 
0601     vio->hs_state |= VIO_HS_GOT_RDX_ACK;
0602     return 0;
0603 }
0604 
0605 static int process_rdx_nack(struct vio_driver_state *vio, struct vio_rdx *pkt)
0606 {
0607     viodbg(HS, "GOT RDX NACK\n");
0608 
0609     return handshake_failure(vio);
0610 }
0611 
0612 static int process_rdx(struct vio_driver_state *vio, struct vio_rdx *pkt)
0613 {
0614     if (!all_drings_registered(vio))
0615         handshake_failure(vio);
0616 
0617     switch (pkt->tag.stype) {
0618     case VIO_SUBTYPE_INFO:
0619         return process_rdx_info(vio, pkt);
0620 
0621     case VIO_SUBTYPE_ACK:
0622         return process_rdx_ack(vio, pkt);
0623 
0624     case VIO_SUBTYPE_NACK:
0625         return process_rdx_nack(vio, pkt);
0626 
0627     default:
0628         return handshake_failure(vio);
0629     }
0630 }
0631 
0632 int vio_control_pkt_engine(struct vio_driver_state *vio, void *pkt)
0633 {
0634     struct vio_msg_tag *tag = pkt;
0635     u8 prev_state = vio->hs_state;
0636     int err;
0637 
0638     switch (tag->stype_env) {
0639     case VIO_VER_INFO:
0640         err = process_ver(vio, pkt);
0641         break;
0642 
0643     case VIO_ATTR_INFO:
0644         err = process_attr(vio, pkt);
0645         break;
0646 
0647     case VIO_DRING_REG:
0648         err = process_dreg(vio, pkt);
0649         break;
0650 
0651     case VIO_DRING_UNREG:
0652         err = process_dunreg(vio, pkt);
0653         break;
0654 
0655     case VIO_RDX:
0656         err = process_rdx(vio, pkt);
0657         break;
0658 
0659     default:
0660         err = process_unknown(vio, pkt);
0661         break;
0662     }
0663 
0664     if (!err &&
0665         vio->hs_state != prev_state &&
0666         (vio->hs_state & VIO_HS_COMPLETE)) {
0667         if (vio->ops)
0668             vio->ops->handshake_complete(vio);
0669     }
0670 
0671     return err;
0672 }
0673 EXPORT_SYMBOL(vio_control_pkt_engine);
0674 
0675 void vio_conn_reset(struct vio_driver_state *vio)
0676 {
0677 }
0678 EXPORT_SYMBOL(vio_conn_reset);
0679 
0680 /* The issue is that the Solaris virtual disk server just mirrors the
0681  * SID values it gets from the client peer.  So we work around that
0682  * here in vio_{validate,send}_sid() so that the drivers don't need
0683  * to be aware of this crap.
0684  */
0685 int vio_validate_sid(struct vio_driver_state *vio, struct vio_msg_tag *tp)
0686 {
0687     u32 sid;
0688 
0689     /* Always let VERSION+INFO packets through unchecked, they
0690      * define the new SID.
0691      */
0692     if (tp->type == VIO_TYPE_CTRL &&
0693         tp->stype == VIO_SUBTYPE_INFO &&
0694         tp->stype_env == VIO_VER_INFO)
0695         return 0;
0696 
0697     /* Ok, now figure out which SID to use.  */
0698     switch (vio->dev_class) {
0699     case VDEV_NETWORK:
0700     case VDEV_NETWORK_SWITCH:
0701     case VDEV_DISK_SERVER:
0702     default:
0703         sid = vio->_peer_sid;
0704         break;
0705 
0706     case VDEV_DISK:
0707         sid = vio->_local_sid;
0708         break;
0709     }
0710 
0711     if (sid == tp->sid)
0712         return 0;
0713     viodbg(DATA, "BAD SID tag->sid[%08x] peer_sid[%08x] local_sid[%08x]\n",
0714            tp->sid, vio->_peer_sid, vio->_local_sid);
0715     return -EINVAL;
0716 }
0717 EXPORT_SYMBOL(vio_validate_sid);
0718 
0719 u32 vio_send_sid(struct vio_driver_state *vio)
0720 {
0721     switch (vio->dev_class) {
0722     case VDEV_NETWORK:
0723     case VDEV_NETWORK_SWITCH:
0724     case VDEV_DISK:
0725     default:
0726         return vio->_local_sid;
0727 
0728     case VDEV_DISK_SERVER:
0729         return vio->_peer_sid;
0730     }
0731 }
0732 EXPORT_SYMBOL(vio_send_sid);
0733 
0734 int vio_ldc_alloc(struct vio_driver_state *vio,
0735              struct ldc_channel_config *base_cfg,
0736              void *event_arg)
0737 {
0738     struct ldc_channel_config cfg = *base_cfg;
0739     struct ldc_channel *lp;
0740 
0741     cfg.tx_irq = vio->vdev->tx_irq;
0742     cfg.rx_irq = vio->vdev->rx_irq;
0743 
0744     lp = ldc_alloc(vio->vdev->channel_id, &cfg, event_arg, vio->name);
0745     if (IS_ERR(lp))
0746         return PTR_ERR(lp);
0747 
0748     vio->lp = lp;
0749 
0750     return 0;
0751 }
0752 EXPORT_SYMBOL(vio_ldc_alloc);
0753 
0754 void vio_ldc_free(struct vio_driver_state *vio)
0755 {
0756     ldc_free(vio->lp);
0757     vio->lp = NULL;
0758 
0759     kfree(vio->desc_buf);
0760     vio->desc_buf = NULL;
0761     vio->desc_buf_len = 0;
0762 }
0763 EXPORT_SYMBOL(vio_ldc_free);
0764 
0765 void vio_port_up(struct vio_driver_state *vio)
0766 {
0767     unsigned long flags;
0768     int err, state;
0769 
0770     spin_lock_irqsave(&vio->lock, flags);
0771 
0772     state = ldc_state(vio->lp);
0773 
0774     err = 0;
0775     if (state == LDC_STATE_INIT) {
0776         err = ldc_bind(vio->lp);
0777         if (err)
0778             printk(KERN_WARNING "%s: Port %lu bind failed, "
0779                    "err=%d\n",
0780                    vio->name, vio->vdev->channel_id, err);
0781     }
0782 
0783     if (!err) {
0784         if (ldc_mode(vio->lp) == LDC_MODE_RAW)
0785             ldc_set_state(vio->lp, LDC_STATE_CONNECTED);
0786         else
0787             err = ldc_connect(vio->lp);
0788 
0789         if (err)
0790             printk(KERN_WARNING "%s: Port %lu connect failed, "
0791                    "err=%d\n",
0792                    vio->name, vio->vdev->channel_id, err);
0793     }
0794     if (err) {
0795         unsigned long expires = jiffies + HZ;
0796 
0797         expires = round_jiffies(expires);
0798         mod_timer(&vio->timer, expires);
0799     }
0800 
0801     spin_unlock_irqrestore(&vio->lock, flags);
0802 }
0803 EXPORT_SYMBOL(vio_port_up);
0804 
0805 static void vio_port_timer(struct timer_list *t)
0806 {
0807     struct vio_driver_state *vio = from_timer(vio, t, timer);
0808 
0809     vio_port_up(vio);
0810 }
0811 
0812 int vio_driver_init(struct vio_driver_state *vio, struct vio_dev *vdev,
0813             u8 dev_class, struct vio_version *ver_table,
0814             int ver_table_size, struct vio_driver_ops *ops,
0815             char *name)
0816 {
0817     switch (dev_class) {
0818     case VDEV_NETWORK:
0819     case VDEV_NETWORK_SWITCH:
0820     case VDEV_DISK:
0821     case VDEV_DISK_SERVER:
0822     case VDEV_CONSOLE_CON:
0823         break;
0824 
0825     default:
0826         return -EINVAL;
0827     }
0828 
0829     if (dev_class == VDEV_NETWORK ||
0830         dev_class == VDEV_NETWORK_SWITCH ||
0831         dev_class == VDEV_DISK ||
0832         dev_class == VDEV_DISK_SERVER) {
0833         if (!ops || !ops->send_attr || !ops->handle_attr ||
0834             !ops->handshake_complete)
0835             return -EINVAL;
0836     }
0837 
0838     if (!ver_table || ver_table_size < 0)
0839         return -EINVAL;
0840 
0841     if (!name)
0842         return -EINVAL;
0843 
0844     spin_lock_init(&vio->lock);
0845 
0846     vio->name = name;
0847 
0848     vio->dev_class = dev_class;
0849     vio->vdev = vdev;
0850 
0851     vio->ver_table = ver_table;
0852     vio->ver_table_entries = ver_table_size;
0853 
0854     vio->ops = ops;
0855 
0856     timer_setup(&vio->timer, vio_port_timer, 0);
0857 
0858     return 0;
0859 }
0860 EXPORT_SYMBOL(vio_driver_init);