aoecmd.c

来自「LINUX 2.6.17.4的源码」· C语言 代码 · 共 709 行 · 第 1/2 页

C
709
字号
/* Copyright (c) 2004 Coraid, Inc.  See COPYING for GPL terms. *//* * aoecmd.c * Filesystem request handling methods */#include <linux/hdreg.h>#include <linux/blkdev.h>#include <linux/skbuff.h>#include <linux/netdevice.h>#include <linux/genhd.h>#include <asm/unaligned.h>#include "aoe.h"#define TIMERTICK (HZ / 10)#define MINTIMER (2 * TIMERTICK)#define MAXTIMER (HZ << 1)#define MAXWAIT (60 * 3)	/* After MAXWAIT seconds, give up and fail dev */static struct sk_buff *new_skb(struct net_device *if_dev, ulong len){	struct sk_buff *skb;	skb = alloc_skb(len, GFP_ATOMIC);	if (skb) {		skb->nh.raw = skb->mac.raw = skb->data;		skb->dev = if_dev;		skb->protocol = __constant_htons(ETH_P_AOE);		skb->priority = 0;		skb_put(skb, len);		memset(skb->head, 0, len);		skb->next = skb->prev = NULL;		/* tell the network layer not to perform IP checksums		 * or to get the NIC to do it		 */		skb->ip_summed = CHECKSUM_NONE;	}	return skb;}static struct sk_buff *skb_prepare(struct aoedev *d, struct frame *f){	struct sk_buff *skb;	char *p;	skb = new_skb(d->ifp, f->ndata + f->writedatalen);	if (!skb) {		printk(KERN_INFO "aoe: skb_prepare: failure to allocate skb\n");		return NULL;	}	p = skb->mac.raw;	memcpy(p, f->data, f->ndata);	if (f->writedatalen) {		p += sizeof(struct aoe_hdr) + sizeof(struct aoe_atahdr);		memcpy(p, f->bufaddr, f->writedatalen);	}	return skb;}static struct frame *getframe(struct aoedev *d, int tag){	struct frame *f, *e;	f = d->frames;	e = f + d->nframes;	for (; f<e; f++)		if (f->tag == tag)			return f;	return NULL;}/* * Leave the top bit clear so we have tagspace for userland. * The bottom 16 bits are the xmit tick for rexmit/rttavg processing. * This driver reserves tag -1 to mean "unused frame." */static intnewtag(struct aoedev *d){	register ulong n;	n = jiffies & 0xffff;	return n |= (++d->lasttag & 0x7fff) << 16;}static intaoehdr_atainit(struct aoedev *d, struct aoe_hdr *h){	u32 host_tag = newtag(d);	memcpy(h->src, d->ifp->dev_addr, sizeof h->src);	memcpy(h->dst, d->addr, sizeof h->dst);	h->type = __constant_cpu_to_be16(ETH_P_AOE);	h->verfl = AOE_HVER;	h->major = cpu_to_be16(d->aoemajor);	h->minor = d->aoeminor;	h->cmd = AOECMD_ATA;	h->tag = cpu_to_be32(host_tag);	return host_tag;}static voidaoecmd_ata_rw(struct aoedev *d, struct frame *f){	struct aoe_hdr *h;	struct aoe_atahdr *ah;	struct buf *buf;	struct sk_buff *skb;	ulong bcnt;	register sector_t sector;	char writebit, extbit;	writebit = 0x10;	extbit = 0x4;	buf = d->inprocess;	sector = buf->sector;	bcnt = buf->bv_resid;	if (bcnt > MAXATADATA)		bcnt = MAXATADATA;	/* initialize the headers & frame */	h = (struct aoe_hdr *) f->data;	ah = (struct aoe_atahdr *) (h+1);	f->ndata = sizeof *h + sizeof *ah;	memset(h, 0, f->ndata);	f->tag = aoehdr_atainit(d, h);	f->waited = 0;	f->buf = buf;	f->bufaddr = buf->bufaddr;	/* set up ata header */	ah->scnt = bcnt >> 9;	ah->lba0 = sector;	ah->lba1 = sector >>= 8;	ah->lba2 = sector >>= 8;	ah->lba3 = sector >>= 8;	if (d->flags & DEVFL_EXT) {		ah->aflags |= AOEAFL_EXT;		ah->lba4 = sector >>= 8;		ah->lba5 = sector >>= 8;	} else {		extbit = 0;		ah->lba3 &= 0x0f;		ah->lba3 |= 0xe0;	/* LBA bit + obsolete 0xa0 */	}	if (bio_data_dir(buf->bio) == WRITE) {		ah->aflags |= AOEAFL_WRITE;		f->writedatalen = bcnt;	} else {		writebit = 0;		f->writedatalen = 0;	}	ah->cmdstat = WIN_READ | writebit | extbit;	/* mark all tracking fields and load out */	buf->nframesout += 1;	buf->bufaddr += bcnt;	buf->bv_resid -= bcnt;/* printk(KERN_INFO "aoe: bv_resid=%ld\n", buf->bv_resid); */	buf->resid -= bcnt;	buf->sector += bcnt >> 9;	if (buf->resid == 0) {		d->inprocess = NULL;	} else if (buf->bv_resid == 0) {		buf->bv++;		buf->bv_resid = buf->bv->bv_len;		buf->bufaddr = page_address(buf->bv->bv_page) + buf->bv->bv_offset;	}	skb = skb_prepare(d, f);	if (skb) {		skb->next = NULL;		if (d->sendq_hd)			d->sendq_tl->next = skb;		else			d->sendq_hd = skb;		d->sendq_tl = skb;	}}/* some callers cannot sleep, and they can call this function, * transmitting the packets later, when interrupts are on */static struct sk_buff *aoecmd_cfg_pkts(ushort aoemajor, unsigned char aoeminor, struct sk_buff **tail){	struct aoe_hdr *h;	struct aoe_cfghdr *ch;	struct sk_buff *skb, *sl, *sl_tail;	struct net_device *ifp;	sl = sl_tail = NULL;	read_lock(&dev_base_lock);	for (ifp = dev_base; ifp; dev_put(ifp), ifp = ifp->next) {		dev_hold(ifp);		if (!is_aoe_netif(ifp))			continue;		skb = new_skb(ifp, sizeof *h + sizeof *ch);		if (skb == NULL) {			printk(KERN_INFO "aoe: aoecmd_cfg: skb alloc failure\n");			continue;		}		if (sl_tail == NULL)			sl_tail = skb;		h = (struct aoe_hdr *) skb->mac.raw;		memset(h, 0, sizeof *h + sizeof *ch);		memset(h->dst, 0xff, sizeof h->dst);		memcpy(h->src, ifp->dev_addr, sizeof h->src);		h->type = __constant_cpu_to_be16(ETH_P_AOE);		h->verfl = AOE_HVER;		h->major = cpu_to_be16(aoemajor);		h->minor = aoeminor;		h->cmd = AOECMD_CFG;		skb->next = sl;		sl = skb;	}	read_unlock(&dev_base_lock);	if (tail != NULL)		*tail = sl_tail;	return sl;}/* enters with d->lock held */voidaoecmd_work(struct aoedev *d){	struct frame *f;	struct buf *buf;	if (d->flags & DEVFL_PAUSE) {		if (!aoedev_isbusy(d))			d->sendq_hd = aoecmd_cfg_pkts(d->aoemajor,						d->aoeminor, &d->sendq_tl);		return;	}loop:	f = getframe(d, FREETAG);	if (f == NULL)		return;	if (d->inprocess == NULL) {		if (list_empty(&d->bufq))			return;		buf = container_of(d->bufq.next, struct buf, bufs);		list_del(d->bufq.next);/*printk(KERN_INFO "aoecmd_work: bi_size=%ld\n", buf->bio->bi_size); */		d->inprocess = buf;	}	aoecmd_ata_rw(d, f);	goto loop;}static voidrexmit(struct aoedev *d, struct frame *f){	struct sk_buff *skb;	struct aoe_hdr *h;	char buf[128];	u32 n;	n = newtag(d);	snprintf(buf, sizeof buf,		"%15s e%ld.%ld oldtag=%08x@%08lx newtag=%08x\n",		"retransmit",		d->aoemajor, d->aoeminor, f->tag, jiffies, n);	aoechr_error(buf);	h = (struct aoe_hdr *) f->data;	f->tag = n;	h->tag = cpu_to_be32(n);	memcpy(h->dst, d->addr, sizeof h->dst);	memcpy(h->src, d->ifp->dev_addr, sizeof h->src);	skb = skb_prepare(d, f);	if (skb) {		skb->next = NULL;		if (d->sendq_hd)			d->sendq_tl->next = skb;		else			d->sendq_hd = skb;		d->sendq_tl = skb;	}}static inttsince(int tag){	int n;	n = jiffies & 0xffff;	n -= tag & 0xffff;	if (n < 0)		n += 1<<16;	return n;}static voidrexmit_timer(ulong vp){	struct aoedev *d;	struct frame *f, *e;	struct sk_buff *sl;	register long timeout;	ulong flags, n;	d = (struct aoedev *) vp;	sl = NULL;	/* timeout is always ~150% of the moving average */	timeout = d->rttavg;	timeout += timeout >> 1;	spin_lock_irqsave(&d->lock, flags);	if (d->flags & DEVFL_TKILL) {		spin_unlock_irqrestore(&d->lock, flags);		return;	}	f = d->frames;	e = f + d->nframes;	for (; f<e; f++) {		if (f->tag != FREETAG && tsince(f->tag) >= timeout) {			n = f->waited += timeout;			n /= HZ;			if (n > MAXWAIT) { /* waited too long.  device failure. */				aoedev_downdev(d);				break;			}			rexmit(d, f);		}	}	sl = d->sendq_hd;	d->sendq_hd = d->sendq_tl = NULL;	if (sl) {		n = d->rttavg <<= 1;		if (n > MAXTIMER)

⌨️ 快捷键说明

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