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