aoecmd.c

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

C
801
字号
	d->timer.expires = jiffies + TIMERTICK;	add_timer(&d->timer);	spin_unlock_irqrestore(&d->lock, flags);	aoenet_xmit(sl);}/* this function performs work that has been deferred until sleeping is OK */voidaoecmd_sleepwork(struct work_struct *work){	struct aoedev *d = container_of(work, struct aoedev, work);	if (d->flags & DEVFL_GDALLOC)		aoeblk_gdalloc(d);	if (d->flags & DEVFL_NEWSIZE) {		struct block_device *bd;		unsigned long flags;		u64 ssize;		ssize = d->gd->capacity;		bd = bdget_disk(d->gd, 0);		if (bd) {			mutex_lock(&bd->bd_inode->i_mutex);			i_size_write(bd->bd_inode, (loff_t)ssize<<9);			mutex_unlock(&bd->bd_inode->i_mutex);			bdput(bd);		}		spin_lock_irqsave(&d->lock, flags);		d->flags |= DEVFL_UP;		d->flags &= ~DEVFL_NEWSIZE;		spin_unlock_irqrestore(&d->lock, flags);	}}static voidataid_complete(struct aoedev *d, unsigned char *id){	u64 ssize;	u16 n;	/* word 83: command set supported */	n = le16_to_cpu(get_unaligned((__le16 *) &id[83<<1]));	/* word 86: command set/feature enabled */	n |= le16_to_cpu(get_unaligned((__le16 *) &id[86<<1]));	if (n & (1<<10)) {	/* bit 10: LBA 48 */		d->flags |= DEVFL_EXT;		/* word 100: number lba48 sectors */		ssize = le64_to_cpu(get_unaligned((__le64 *) &id[100<<1]));		/* set as in ide-disk.c:init_idedisk_capacity */		d->geo.cylinders = ssize;		d->geo.cylinders /= (255 * 63);		d->geo.heads = 255;		d->geo.sectors = 63;	} else {		d->flags &= ~DEVFL_EXT;		/* number lba28 sectors */		ssize = le32_to_cpu(get_unaligned((__le32 *) &id[60<<1]));		/* NOTE: obsolete in ATA 6 */		d->geo.cylinders = le16_to_cpu(get_unaligned((__le16 *) &id[54<<1]));		d->geo.heads = le16_to_cpu(get_unaligned((__le16 *) &id[55<<1]));		d->geo.sectors = le16_to_cpu(get_unaligned((__le16 *) &id[56<<1]));	}	if (d->ssize != ssize)		printk(KERN_INFO "aoe: %012llx e%lu.%lu v%04x has %llu sectors\n",			(unsigned long long)mac_addr(d->addr),			d->aoemajor, d->aoeminor,			d->fw_ver, (long long)ssize);	d->ssize = ssize;	d->geo.start = 0;	if (d->gd != NULL) {		d->gd->capacity = ssize;		d->flags |= DEVFL_NEWSIZE;	} else {		if (d->flags & DEVFL_GDALLOC) {			printk(KERN_ERR "aoe: can't schedule work for e%lu.%lu, %s\n",			       d->aoemajor, d->aoeminor,			       "it's already on!  This shouldn't happen.\n");			return;		}		d->flags |= DEVFL_GDALLOC;	}	schedule_work(&d->work);}static voidcalc_rttavg(struct aoedev *d, int rtt){	register long n;	n = rtt;	if (n < 0) {		n = -rtt;		if (n < MINTIMER)			n = MINTIMER;		else if (n > MAXTIMER)			n = MAXTIMER;		d->mintimer += (n - d->mintimer) >> 1;	} else if (n < d->mintimer)		n = d->mintimer;	else if (n > MAXTIMER)		n = MAXTIMER;	/* g == .25; cf. Congestion Avoidance and Control, Jacobson & Karels; 1988 */	n -= d->rttavg;	d->rttavg += n >> 2;}voidaoecmd_ata_rsp(struct sk_buff *skb){	struct aoedev *d;	struct aoe_hdr *hin, *hout;	struct aoe_atahdr *ahin, *ahout;	struct frame *f;	struct buf *buf;	struct sk_buff *sl;	register long n;	ulong flags;	char ebuf[128];	u16 aoemajor;	hin = (struct aoe_hdr *) skb_mac_header(skb);	aoemajor = be16_to_cpu(get_unaligned(&hin->major));	d = aoedev_by_aoeaddr(aoemajor, hin->minor);	if (d == NULL) {		snprintf(ebuf, sizeof ebuf, "aoecmd_ata_rsp: ata response "			"for unknown device %d.%d\n",			 aoemajor, hin->minor);		aoechr_error(ebuf);		return;	}	spin_lock_irqsave(&d->lock, flags);	n = be32_to_cpu(get_unaligned(&hin->tag));	f = getframe(d, n);	if (f == NULL) {		calc_rttavg(d, -tsince(n));		spin_unlock_irqrestore(&d->lock, flags);		snprintf(ebuf, sizeof ebuf,			"%15s e%d.%d    tag=%08x@%08lx\n",			"unexpected rsp",			be16_to_cpu(get_unaligned(&hin->major)),			hin->minor,			be32_to_cpu(get_unaligned(&hin->tag)),			jiffies);		aoechr_error(ebuf);		return;	}	calc_rttavg(d, tsince(f->tag));	ahin = (struct aoe_atahdr *) (hin+1);	hout = (struct aoe_hdr *) skb_mac_header(f->skb);	ahout = (struct aoe_atahdr *) (hout+1);	buf = f->buf;	if (ahout->cmdstat == WIN_IDENTIFY)		d->flags &= ~DEVFL_PAUSE;	if (ahin->cmdstat & 0xa9) {	/* these bits cleared on success */		printk(KERN_ERR			"aoe: ata error cmd=%2.2Xh stat=%2.2Xh from e%ld.%ld\n",			ahout->cmdstat, ahin->cmdstat,			d->aoemajor, d->aoeminor);		if (buf)			buf->flags |= BUFFL_FAIL;	} else {		n = ahout->scnt << 9;		switch (ahout->cmdstat) {		case WIN_READ:		case WIN_READ_EXT:			if (skb->len - sizeof *hin - sizeof *ahin < n) {				printk(KERN_ERR					"aoe: runt data size in read.  skb->len=%d\n",					skb->len);				/* fail frame f?  just returning will rexmit. */				spin_unlock_irqrestore(&d->lock, flags);				return;			}			memcpy(f->bufaddr, ahin+1, n);		case WIN_WRITE:		case WIN_WRITE_EXT:			if (f->bcnt -= n) {				skb = f->skb;				f->bufaddr += n;				put_lba(ahout, f->lba += ahout->scnt);				n = f->bcnt;				if (n > DEFAULTBCNT)					n = DEFAULTBCNT;				ahout->scnt = n >> 9;				if (ahout->aflags & AOEAFL_WRITE) {					skb_fill_page_desc(skb, 0,						virt_to_page(f->bufaddr),						offset_in_page(f->bufaddr), n);					skb->len = sizeof *hout + sizeof *ahout + n;					skb->data_len = n;				}				f->tag = newtag(d);				hout->tag = cpu_to_be32(f->tag);				skb->dev = d->ifp;				skb = skb_clone(skb, GFP_ATOMIC);				spin_unlock_irqrestore(&d->lock, flags);				if (skb)					aoenet_xmit(skb);				return;			}			if (n > DEFAULTBCNT)				d->lostjumbo = 0;			break;		case WIN_IDENTIFY:			if (skb->len - sizeof *hin - sizeof *ahin < 512) {				printk(KERN_INFO					"aoe: runt data size in ataid.  skb->len=%d\n",					skb->len);				spin_unlock_irqrestore(&d->lock, flags);				return;			}			ataid_complete(d, (char *) (ahin+1));			break;		default:			printk(KERN_INFO				"aoe: unrecognized ata command %2.2Xh for %d.%d\n",				ahout->cmdstat,				be16_to_cpu(get_unaligned(&hin->major)),				hin->minor);		}	}	if (buf) {		buf->nframesout -= 1;		if (buf->nframesout == 0 && buf->resid == 0) {			unsigned long duration = jiffies - buf->start_time;			unsigned long n_sect = buf->bio->bi_size >> 9;			struct gendisk *disk = d->gd;			const int rw = bio_data_dir(buf->bio);			disk_stat_inc(disk, ios[rw]);			disk_stat_add(disk, ticks[rw], duration);			disk_stat_add(disk, sectors[rw], n_sect);			disk_stat_add(disk, io_ticks, duration);			n = (buf->flags & BUFFL_FAIL) ? -EIO : 0;			bio_endio(buf->bio, n);			mempool_free(buf, d->bufpool);		}	}	f->buf = NULL;	f->tag = FREETAG;	aoecmd_work(d);	sl = d->sendq_hd;	d->sendq_hd = d->sendq_tl = NULL;	spin_unlock_irqrestore(&d->lock, flags);	aoenet_xmit(sl);}voidaoecmd_cfg(ushort aoemajor, unsigned char aoeminor){	struct sk_buff *sl;	sl = aoecmd_cfg_pkts(aoemajor, aoeminor, NULL);	aoenet_xmit(sl);} /* * Since we only call this in one place (and it only prepares one frame) * we just return the skb.  Usually we'd chain it up to the aoedev sendq. */static struct sk_buff *aoecmd_ata_id(struct aoedev *d){	struct aoe_hdr *h;	struct aoe_atahdr *ah;	struct frame *f;	struct sk_buff *skb;	f = freeframe(d);	if (f == NULL) {		printk(KERN_ERR "aoe: can't get a frame. This shouldn't happen.\n");		return NULL;	}	/* initialize the headers & frame */	skb = f->skb;	h = (struct aoe_hdr *) skb_mac_header(skb);	ah = (struct aoe_atahdr *) (h+1);	skb_put(skb, sizeof *h + sizeof *ah);	memset(h, 0, skb->len);	f->tag = aoehdr_atainit(d, h);	f->waited = 0;	/* set up ata header */	ah->scnt = 1;	ah->cmdstat = WIN_IDENTIFY;	ah->lba3 = 0xa0;	skb->dev = d->ifp;	d->rttavg = MAXTIMER;	d->timer.function = rexmit_timer;	return skb_clone(skb, GFP_ATOMIC);} voidaoecmd_cfg_rsp(struct sk_buff *skb){	struct aoedev *d;	struct aoe_hdr *h;	struct aoe_cfghdr *ch;	ulong flags, sysminor, aoemajor;	struct sk_buff *sl;	enum { MAXFRAMES = 16 };	u16 n;	h = (struct aoe_hdr *) skb_mac_header(skb);	ch = (struct aoe_cfghdr *) (h+1);	/*	 * Enough people have their dip switches set backwards to	 * warrant a loud message for this special case.	 */	aoemajor = be16_to_cpu(get_unaligned(&h->major));	if (aoemajor == 0xfff) {		printk(KERN_ERR "aoe: Warning: shelf address is all ones.  "			"Check shelf dip switches.\n");		return;	}	sysminor = SYSMINOR(aoemajor, h->minor);	if (sysminor * AOE_PARTITIONS + AOE_PARTITIONS > MINORMASK) {		printk(KERN_INFO "aoe: e%ld.%d: minor number too large\n",			aoemajor, (int) h->minor);		return;	}	n = be16_to_cpu(ch->bufcnt);	if (n > MAXFRAMES)	/* keep it reasonable */		n = MAXFRAMES;	d = aoedev_by_sysminor_m(sysminor, n);	if (d == NULL) {		printk(KERN_INFO "aoe: device sysminor_m failure\n");		return;	}	spin_lock_irqsave(&d->lock, flags);	/* permit device to migrate mac and network interface */	d->ifp = skb->dev;	memcpy(d->addr, h->src, sizeof d->addr);	if (!(d->flags & DEVFL_MAXBCNT)) {		n = d->ifp->mtu;		n -= sizeof (struct aoe_hdr) + sizeof (struct aoe_atahdr);		n /= 512;		if (n > ch->scnt)			n = ch->scnt;		n = n ? n * 512 : DEFAULTBCNT;		if (n != d->maxbcnt) {			printk(KERN_INFO				"aoe: e%ld.%ld: setting %d byte data frames on %s\n",				d->aoemajor, d->aoeminor, n, d->ifp->name);			d->maxbcnt = n;		}	}	/* don't change users' perspective */	if (d->nopen && !(d->flags & DEVFL_PAUSE)) {		spin_unlock_irqrestore(&d->lock, flags);		return;	}	d->flags |= DEVFL_PAUSE;	/* force pause */	d->mintimer = MINTIMER;	d->fw_ver = be16_to_cpu(ch->fwver);	/* check for already outstanding ataid */	sl = aoedev_isbusy(d) == 0 ? aoecmd_ata_id(d) : NULL;	spin_unlock_irqrestore(&d->lock, flags);	aoenet_xmit(sl);}

⌨️ 快捷键说明

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