viohs.c

来自「linux 内核源代码」· C语言 代码 · 共 823 行 · 第 1/2 页

C
823
字号
	int i, len;	viodbg(HS, "GOT DRING_REG INFO ident[%llx] "	       "ndesc[%u] dsz[%u] opt[0x%x] ncookies[%u]\n",	       (unsigned long long) pkt->dring_ident,	       pkt->num_descr, pkt->descr_size, pkt->options,	       pkt->num_cookies);	if (!(vio->dr_state & VIO_DR_STATE_RXREQ))		goto send_nack;	if (vio->dr_state & VIO_DR_STATE_RXREG)		goto send_nack;	BUG_ON(vio->desc_buf);	vio->desc_buf = kzalloc(pkt->descr_size, GFP_ATOMIC);	if (!vio->desc_buf)		goto send_nack;	vio->desc_buf_len = pkt->descr_size;	dr = &vio->drings[VIO_DRIVER_RX_RING];	dr->num_entries = pkt->num_descr;	dr->entry_size = pkt->descr_size;	dr->ncookies = pkt->num_cookies;	for (i = 0; i < dr->ncookies; i++) {		dr->cookies[i] = pkt->cookies[i];		viodbg(HS, "DRING COOKIE(%d) [%016llx:%016llx]\n",		       i,		       (unsigned long long)		       pkt->cookies[i].cookie_addr,		       (unsigned long long)		       pkt->cookies[i].cookie_size);	}	pkt->tag.stype = VIO_SUBTYPE_ACK;	pkt->dring_ident = ++dr->ident;	viodbg(HS, "SEND DRING_REG ACK ident[%llx]\n",	       (unsigned long long) pkt->dring_ident);	len = (sizeof(*pkt) +	       (dr->ncookies * sizeof(struct ldc_trans_cookie)));	if (send_ctrl(vio, &pkt->tag, len) < 0)		goto send_nack;	vio->dr_state |= VIO_DR_STATE_RXREG;	return 0;send_nack:	pkt->tag.stype = VIO_SUBTYPE_NACK;	viodbg(HS, "SEND DRING_REG NACK\n");	(void) send_ctrl(vio, &pkt->tag, sizeof(*pkt));	return handshake_failure(vio);}static int process_dreg_ack(struct vio_driver_state *vio,			    struct vio_dring_register *pkt){	struct vio_dring_state *dr;	viodbg(HS, "GOT DRING_REG ACK ident[%llx] "	       "ndesc[%u] dsz[%u] opt[0x%x] ncookies[%u]\n",	       (unsigned long long) pkt->dring_ident,	       pkt->num_descr, pkt->descr_size, pkt->options,	       pkt->num_cookies);	dr = &vio->drings[VIO_DRIVER_TX_RING];	if (!(vio->dr_state & VIO_DR_STATE_TXREQ))		return handshake_failure(vio);	dr->ident = pkt->dring_ident;	vio->dr_state |= VIO_DR_STATE_TXREG;	if (all_drings_registered(vio)) {		if (send_rdx(vio) < 0)			return handshake_failure(vio);		vio->hs_state = VIO_HS_SENT_RDX;	}	return 0;}static int process_dreg_nack(struct vio_driver_state *vio,			     struct vio_dring_register *pkt){	viodbg(HS, "GOT DRING_REG NACK ident[%llx] "	       "ndesc[%u] dsz[%u] opt[0x%x] ncookies[%u]\n",	       (unsigned long long) pkt->dring_ident,	       pkt->num_descr, pkt->descr_size, pkt->options,	       pkt->num_cookies);	return handshake_failure(vio);}static int process_dreg(struct vio_driver_state *vio,			struct vio_dring_register *pkt){	if (!(vio->hs_state & VIO_HS_GOTVERS))		return handshake_failure(vio);	switch (pkt->tag.stype) {	case VIO_SUBTYPE_INFO:		return process_dreg_info(vio, pkt);	case VIO_SUBTYPE_ACK:		return process_dreg_ack(vio, pkt);	case VIO_SUBTYPE_NACK:		return process_dreg_nack(vio, pkt);	default:		return handshake_failure(vio);	}}static int process_dunreg(struct vio_driver_state *vio,			  struct vio_dring_unregister *pkt){	struct vio_dring_state *dr = &vio->drings[VIO_DRIVER_RX_RING];	viodbg(HS, "GOT DRING_UNREG\n");	if (pkt->dring_ident != dr->ident)		return 0;	vio->dr_state &= ~VIO_DR_STATE_RXREG;	memset(dr, 0, sizeof(*dr));	kfree(vio->desc_buf);	vio->desc_buf = NULL;	vio->desc_buf_len = 0;	return 0;}static int process_rdx_info(struct vio_driver_state *vio, struct vio_rdx *pkt){	viodbg(HS, "GOT RDX INFO\n");	pkt->tag.stype = VIO_SUBTYPE_ACK;	viodbg(HS, "SEND RDX ACK\n");	if (send_ctrl(vio, &pkt->tag, sizeof(*pkt)) < 0)		return handshake_failure(vio);	vio->hs_state |= VIO_HS_SENT_RDX_ACK;	return 0;}static int process_rdx_ack(struct vio_driver_state *vio, struct vio_rdx *pkt){	viodbg(HS, "GOT RDX ACK\n");	if (!(vio->hs_state & VIO_HS_SENT_RDX))		return handshake_failure(vio);	vio->hs_state |= VIO_HS_GOT_RDX_ACK;	return 0;}static int process_rdx_nack(struct vio_driver_state *vio, struct vio_rdx *pkt){	viodbg(HS, "GOT RDX NACK\n");	return handshake_failure(vio);}static int process_rdx(struct vio_driver_state *vio, struct vio_rdx *pkt){	if (!all_drings_registered(vio))		handshake_failure(vio);	switch (pkt->tag.stype) {	case VIO_SUBTYPE_INFO:		return process_rdx_info(vio, pkt);	case VIO_SUBTYPE_ACK:		return process_rdx_ack(vio, pkt);	case VIO_SUBTYPE_NACK:		return process_rdx_nack(vio, pkt);	default:		return handshake_failure(vio);	}}int vio_control_pkt_engine(struct vio_driver_state *vio, void *pkt){	struct vio_msg_tag *tag = pkt;	u8 prev_state = vio->hs_state;	int err;	switch (tag->stype_env) {	case VIO_VER_INFO:		err = process_ver(vio, pkt);		break;	case VIO_ATTR_INFO:		err = process_attr(vio, pkt);		break;	case VIO_DRING_REG:		err = process_dreg(vio, pkt);		break;	case VIO_DRING_UNREG:		err = process_dunreg(vio, pkt);		break;	case VIO_RDX:		err = process_rdx(vio, pkt);		break;	default:		err = process_unknown(vio, pkt);		break;	}	if (!err &&	    vio->hs_state != prev_state &&	    (vio->hs_state & VIO_HS_COMPLETE))		vio->ops->handshake_complete(vio);	return err;}EXPORT_SYMBOL(vio_control_pkt_engine);void vio_conn_reset(struct vio_driver_state *vio){}EXPORT_SYMBOL(vio_conn_reset);/* The issue is that the Solaris virtual disk server just mirrors the * SID values it gets from the client peer.  So we work around that * here in vio_{validate,send}_sid() so that the drivers don't need * to be aware of this crap. */int vio_validate_sid(struct vio_driver_state *vio, struct vio_msg_tag *tp){	u32 sid;	/* Always let VERSION+INFO packets through unchecked, they	 * define the new SID.	 */	if (tp->type == VIO_TYPE_CTRL &&	    tp->stype == VIO_SUBTYPE_INFO &&	    tp->stype_env == VIO_VER_INFO)		return 0;	/* Ok, now figure out which SID to use.  */	switch (vio->dev_class) {	case VDEV_NETWORK:	case VDEV_NETWORK_SWITCH:	case VDEV_DISK_SERVER:	default:		sid = vio->_peer_sid;		break;	case VDEV_DISK:		sid = vio->_local_sid;		break;	}	if (sid == tp->sid)		return 0;	viodbg(DATA, "BAD SID tag->sid[%08x] peer_sid[%08x] local_sid[%08x]\n",	       tp->sid, vio->_peer_sid, vio->_local_sid);	return -EINVAL;}EXPORT_SYMBOL(vio_validate_sid);u32 vio_send_sid(struct vio_driver_state *vio){	switch (vio->dev_class) {	case VDEV_NETWORK:	case VDEV_NETWORK_SWITCH:	case VDEV_DISK:	default:		return vio->_local_sid;	case VDEV_DISK_SERVER:		return vio->_peer_sid;	}}EXPORT_SYMBOL(vio_send_sid);int vio_ldc_alloc(struct vio_driver_state *vio,			 struct ldc_channel_config *base_cfg,			 void *event_arg){	struct ldc_channel_config cfg = *base_cfg;	struct ldc_channel *lp;	cfg.tx_irq = vio->vdev->tx_irq;	cfg.rx_irq = vio->vdev->rx_irq;	lp = ldc_alloc(vio->vdev->channel_id, &cfg, event_arg);	if (IS_ERR(lp))		return PTR_ERR(lp);	vio->lp = lp;	return 0;}EXPORT_SYMBOL(vio_ldc_alloc);void vio_ldc_free(struct vio_driver_state *vio){	ldc_free(vio->lp);	vio->lp = NULL;	kfree(vio->desc_buf);	vio->desc_buf = NULL;	vio->desc_buf_len = 0;}EXPORT_SYMBOL(vio_ldc_free);void vio_port_up(struct vio_driver_state *vio){	unsigned long flags;	int err, state;	spin_lock_irqsave(&vio->lock, flags);	state = ldc_state(vio->lp);	err = 0;	if (state == LDC_STATE_INIT) {		err = ldc_bind(vio->lp, vio->name);		if (err)			printk(KERN_WARNING "%s: Port %lu bind failed, "			       "err=%d\n",			       vio->name, vio->vdev->channel_id, err);	}	if (!err) {		err = ldc_connect(vio->lp);		if (err)			printk(KERN_WARNING "%s: Port %lu connect failed, "			       "err=%d\n",			       vio->name, vio->vdev->channel_id, err);	}	if (err) {		unsigned long expires = jiffies + HZ;		expires = round_jiffies(expires);		mod_timer(&vio->timer, expires);	}	spin_unlock_irqrestore(&vio->lock, flags);}EXPORT_SYMBOL(vio_port_up);static void vio_port_timer(unsigned long _arg){	struct vio_driver_state *vio = (struct vio_driver_state *) _arg;	vio_port_up(vio);}int vio_driver_init(struct vio_driver_state *vio, struct vio_dev *vdev,		    u8 dev_class, struct vio_version *ver_table,		    int ver_table_size, struct vio_driver_ops *ops,		    char *name){	switch (dev_class) {	case VDEV_NETWORK:	case VDEV_NETWORK_SWITCH:	case VDEV_DISK:	case VDEV_DISK_SERVER:		break;	default:		return -EINVAL;	}	if (!ops->send_attr ||	    !ops->handle_attr ||	    !ops->handshake_complete)		return -EINVAL;	if (!ver_table || ver_table_size < 0)		return -EINVAL;	if (!name)		return -EINVAL;	spin_lock_init(&vio->lock);	vio->name = name;	vio->dev_class = dev_class;	vio->vdev = vdev;	vio->ver_table = ver_table;	vio->ver_table_entries = ver_table_size;	vio->ops = ops;	setup_timer(&vio->timer, vio_port_timer, (unsigned long) vio);	return 0;}EXPORT_SYMBOL(vio_driver_init);

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?