diff options
Diffstat (limited to 'drivers/block/aoe/aoecmd.c')
-rw-r--r-- | drivers/block/aoe/aoecmd.c | 77 |
1 files changed, 63 insertions, 14 deletions
diff --git a/drivers/block/aoe/aoecmd.c b/drivers/block/aoe/aoecmd.c index 1aeb2969987f..666797d646d6 100644 --- a/drivers/block/aoe/aoecmd.c +++ b/drivers/block/aoe/aoecmd.c | |||
@@ -83,6 +83,17 @@ aoehdr_atainit(struct aoedev *d, struct aoe_hdr *h) | |||
83 | return host_tag; | 83 | return host_tag; |
84 | } | 84 | } |
85 | 85 | ||
86 | static inline void | ||
87 | put_lba(struct aoe_atahdr *ah, sector_t lba) | ||
88 | { | ||
89 | ah->lba0 = lba; | ||
90 | ah->lba1 = lba >>= 8; | ||
91 | ah->lba2 = lba >>= 8; | ||
92 | ah->lba3 = lba >>= 8; | ||
93 | ah->lba4 = lba >>= 8; | ||
94 | ah->lba5 = lba >>= 8; | ||
95 | } | ||
96 | |||
86 | static void | 97 | static void |
87 | aoecmd_ata_rw(struct aoedev *d, struct frame *f) | 98 | aoecmd_ata_rw(struct aoedev *d, struct frame *f) |
88 | { | 99 | { |
@@ -101,8 +112,8 @@ aoecmd_ata_rw(struct aoedev *d, struct frame *f) | |||
101 | 112 | ||
102 | sector = buf->sector; | 113 | sector = buf->sector; |
103 | bcnt = buf->bv_resid; | 114 | bcnt = buf->bv_resid; |
104 | if (bcnt > MAXATADATA) | 115 | if (bcnt > d->maxbcnt) |
105 | bcnt = MAXATADATA; | 116 | bcnt = d->maxbcnt; |
106 | 117 | ||
107 | /* initialize the headers & frame */ | 118 | /* initialize the headers & frame */ |
108 | skb = f->skb; | 119 | skb = f->skb; |
@@ -114,17 +125,14 @@ aoecmd_ata_rw(struct aoedev *d, struct frame *f) | |||
114 | f->waited = 0; | 125 | f->waited = 0; |
115 | f->buf = buf; | 126 | f->buf = buf; |
116 | f->bufaddr = buf->bufaddr; | 127 | f->bufaddr = buf->bufaddr; |
128 | f->bcnt = bcnt; | ||
129 | f->lba = sector; | ||
117 | 130 | ||
118 | /* set up ata header */ | 131 | /* set up ata header */ |
119 | ah->scnt = bcnt >> 9; | 132 | ah->scnt = bcnt >> 9; |
120 | ah->lba0 = sector; | 133 | put_lba(ah, sector); |
121 | ah->lba1 = sector >>= 8; | ||
122 | ah->lba2 = sector >>= 8; | ||
123 | ah->lba3 = sector >>= 8; | ||
124 | if (d->flags & DEVFL_EXT) { | 134 | if (d->flags & DEVFL_EXT) { |
125 | ah->aflags |= AOEAFL_EXT; | 135 | ah->aflags |= AOEAFL_EXT; |
126 | ah->lba4 = sector >>= 8; | ||
127 | ah->lba5 = sector >>= 8; | ||
128 | } else { | 136 | } else { |
129 | extbit = 0; | 137 | extbit = 0; |
130 | ah->lba3 &= 0x0f; | 138 | ah->lba3 &= 0x0f; |
@@ -251,6 +259,7 @@ rexmit(struct aoedev *d, struct frame *f) | |||
251 | { | 259 | { |
252 | struct sk_buff *skb; | 260 | struct sk_buff *skb; |
253 | struct aoe_hdr *h; | 261 | struct aoe_hdr *h; |
262 | struct aoe_atahdr *ah; | ||
254 | char buf[128]; | 263 | char buf[128]; |
255 | u32 n; | 264 | u32 n; |
256 | 265 | ||
@@ -264,11 +273,27 @@ rexmit(struct aoedev *d, struct frame *f) | |||
264 | 273 | ||
265 | skb = f->skb; | 274 | skb = f->skb; |
266 | h = (struct aoe_hdr *) skb->mac.raw; | 275 | h = (struct aoe_hdr *) skb->mac.raw; |
276 | ah = (struct aoe_atahdr *) (h+1); | ||
267 | f->tag = n; | 277 | f->tag = n; |
268 | h->tag = cpu_to_be32(n); | 278 | h->tag = cpu_to_be32(n); |
269 | memcpy(h->dst, d->addr, sizeof h->dst); | 279 | memcpy(h->dst, d->addr, sizeof h->dst); |
270 | memcpy(h->src, d->ifp->dev_addr, sizeof h->src); | 280 | memcpy(h->src, d->ifp->dev_addr, sizeof h->src); |
271 | 281 | ||
282 | n = DEFAULTBCNT / 512; | ||
283 | if (ah->scnt > n) { | ||
284 | ah->scnt = n; | ||
285 | if (ah->aflags & AOEAFL_WRITE) | ||
286 | skb_fill_page_desc(skb, 0, virt_to_page(f->bufaddr), | ||
287 | offset_in_page(f->bufaddr), DEFAULTBCNT); | ||
288 | if (++d->lostjumbo > (d->nframes << 1)) | ||
289 | if (d->maxbcnt != DEFAULTBCNT) { | ||
290 | printk(KERN_INFO "aoe: rexmit: too many lost jumbo. " | ||
291 | "dropping back to 1KB frames.\n"); | ||
292 | d->maxbcnt = DEFAULTBCNT; | ||
293 | d->flags |= DEVFL_MAXBCNT; | ||
294 | } | ||
295 | } | ||
296 | |||
272 | skb->dev = d->ifp; | 297 | skb->dev = d->ifp; |
273 | skb_get(skb); | 298 | skb_get(skb); |
274 | skb->next = NULL; | 299 | skb->next = NULL; |
@@ -506,10 +531,10 @@ aoecmd_ata_rsp(struct sk_buff *skb) | |||
506 | if (buf) | 531 | if (buf) |
507 | buf->flags |= BUFFL_FAIL; | 532 | buf->flags |= BUFFL_FAIL; |
508 | } else { | 533 | } else { |
534 | n = ahout->scnt << 9; | ||
509 | switch (ahout->cmdstat) { | 535 | switch (ahout->cmdstat) { |
510 | case WIN_READ: | 536 | case WIN_READ: |
511 | case WIN_READ_EXT: | 537 | case WIN_READ_EXT: |
512 | n = ahout->scnt << 9; | ||
513 | if (skb->len - sizeof *hin - sizeof *ahin < n) { | 538 | if (skb->len - sizeof *hin - sizeof *ahin < n) { |
514 | printk(KERN_CRIT "aoe: aoecmd_ata_rsp: runt " | 539 | printk(KERN_CRIT "aoe: aoecmd_ata_rsp: runt " |
515 | "ata data size in read. skb->len=%d\n", | 540 | "ata data size in read. skb->len=%d\n", |
@@ -521,6 +546,22 @@ aoecmd_ata_rsp(struct sk_buff *skb) | |||
521 | memcpy(f->bufaddr, ahin+1, n); | 546 | memcpy(f->bufaddr, ahin+1, n); |
522 | case WIN_WRITE: | 547 | case WIN_WRITE: |
523 | case WIN_WRITE_EXT: | 548 | case WIN_WRITE_EXT: |
549 | if (f->bcnt -= n) { | ||
550 | f->bufaddr += n; | ||
551 | put_lba(ahout, f->lba += ahout->scnt); | ||
552 | n = f->bcnt > DEFAULTBCNT ? DEFAULTBCNT : f->bcnt; | ||
553 | ahout->scnt = n >> 9; | ||
554 | if (ahout->aflags & AOEAFL_WRITE) | ||
555 | skb_fill_page_desc(f->skb, 0, virt_to_page(f->bufaddr), | ||
556 | offset_in_page(f->bufaddr), n); | ||
557 | skb_get(f->skb); | ||
558 | f->skb->next = NULL; | ||
559 | spin_unlock_irqrestore(&d->lock, flags); | ||
560 | aoenet_xmit(f->skb); | ||
561 | return; | ||
562 | } | ||
563 | if (n > DEFAULTBCNT) | ||
564 | d->lostjumbo = 0; | ||
524 | break; | 565 | break; |
525 | case WIN_IDENTIFY: | 566 | case WIN_IDENTIFY: |
526 | if (skb->len - sizeof *hin - sizeof *ahin < 512) { | 567 | if (skb->len - sizeof *hin - sizeof *ahin < 512) { |
@@ -628,9 +669,9 @@ aoecmd_cfg_rsp(struct sk_buff *skb) | |||
628 | struct aoe_hdr *h; | 669 | struct aoe_hdr *h; |
629 | struct aoe_cfghdr *ch; | 670 | struct aoe_cfghdr *ch; |
630 | ulong flags, sysminor, aoemajor; | 671 | ulong flags, sysminor, aoemajor; |
631 | u16 bufcnt; | ||
632 | struct sk_buff *sl; | 672 | struct sk_buff *sl; |
633 | enum { MAXFRAMES = 16 }; | 673 | enum { MAXFRAMES = 16 }; |
674 | u16 n; | ||
634 | 675 | ||
635 | h = (struct aoe_hdr *) skb->mac.raw; | 676 | h = (struct aoe_hdr *) skb->mac.raw; |
636 | ch = (struct aoe_cfghdr *) (h+1); | 677 | ch = (struct aoe_cfghdr *) (h+1); |
@@ -654,11 +695,11 @@ aoecmd_cfg_rsp(struct sk_buff *skb) | |||
654 | return; | 695 | return; |
655 | } | 696 | } |
656 | 697 | ||
657 | bufcnt = be16_to_cpu(ch->bufcnt); | 698 | n = be16_to_cpu(ch->bufcnt); |
658 | if (bufcnt > MAXFRAMES) /* keep it reasonable */ | 699 | if (n > MAXFRAMES) /* keep it reasonable */ |
659 | bufcnt = MAXFRAMES; | 700 | n = MAXFRAMES; |
660 | 701 | ||
661 | d = aoedev_by_sysminor_m(sysminor, bufcnt); | 702 | d = aoedev_by_sysminor_m(sysminor, n); |
662 | if (d == NULL) { | 703 | if (d == NULL) { |
663 | printk(KERN_INFO "aoe: aoecmd_cfg_rsp: device sysminor_m failure\n"); | 704 | printk(KERN_INFO "aoe: aoecmd_cfg_rsp: device sysminor_m failure\n"); |
664 | return; | 705 | return; |
@@ -669,6 +710,14 @@ aoecmd_cfg_rsp(struct sk_buff *skb) | |||
669 | /* permit device to migrate mac and network interface */ | 710 | /* permit device to migrate mac and network interface */ |
670 | d->ifp = skb->dev; | 711 | d->ifp = skb->dev; |
671 | memcpy(d->addr, h->src, sizeof d->addr); | 712 | memcpy(d->addr, h->src, sizeof d->addr); |
713 | if (!(d->flags & DEVFL_MAXBCNT)) { | ||
714 | n = d->ifp->mtu; | ||
715 | n -= sizeof (struct aoe_hdr) + sizeof (struct aoe_atahdr); | ||
716 | n /= 512; | ||
717 | if (n > ch->scnt) | ||
718 | n = ch->scnt; | ||
719 | d->maxbcnt = n ? n * 512 : DEFAULTBCNT; | ||
720 | } | ||
672 | 721 | ||
673 | /* don't change users' perspective */ | 722 | /* don't change users' perspective */ |
674 | if (d->nopen && !(d->flags & DEVFL_PAUSE)) { | 723 | if (d->nopen && !(d->flags & DEVFL_PAUSE)) { |