diff -c -r vblade-21/aoe.c vblade-21-patched/aoe.c
*** vblade-21/aoe.c	Fri Aug 14 21:39:26 2009
--- vblade-21-patched/aoe.c	Sun May 11 01:30:58 2014
***************
*** 4,16 ****
--- 4,28 ----
  #include <stdio.h>
  #include <string.h>
  #include <stdlib.h>
+ #include <malloc.h> 
  #include <unistd.h>
+ #include <signal.h>
  #include <sys/types.h>
  #include <sys/stat.h>
+ #include <sys/ioctl.h>
+ #include <sys/mman.h>
  #include <fcntl.h>
  #include <netinet/in.h>
  #include "dat.h"
  #include "fns.h"
+ #include <linux/if_packet.h>
+ #include <netinet/if_ether.h>
+ #include <poll.h>
+ #include <errno.h>
+ #include <assert.h>
+ 
+ 
+ #define USE_RX_RING
  
  enum {
  	Nmasks= 32,
***************
*** 39,47 ****
  	memset(p, 0, sizeof *p);
  	memset(p->h.dst, 0xff, 6);
  	memmove(p->h.src, mac, 6);
! 	p->h.type = htons(0x88a2);
  	p->h.flags = Resp;
! 	p->h.maj = htons(shelf);
  	p->h.min = slot;
  	p->h.cmd = Config;
  	p->bufcnt = htons(bufcnt);
--- 51,59 ----
  	memset(p, 0, sizeof *p);
  	memset(p->h.dst, 0xff, 6);
  	memmove(p->h.src, mac, 6);
! 	p->h.type = type_net;
  	p->h.flags = Resp;
! 	p->h.maj = shelf_net;
  	p->h.min = slot;
  	p->h.cmd = Config;
  	p->bufcnt = htons(bufcnt);
***************
*** 83,89 ****
  }
  
  int
! aoeata(Ata *p, int pktlen)	// do ATA reqeust
  {
  	Ataregs r;
  	int len = 60;
--- 95,101 ----
  }
  
  int
! aoeata(Ata *p, Ata *op, int pktlen)	// do ATA reqeust
  {
  	Ataregs r;
  	int len = 60;
***************
*** 95,117 ****
  	r.cmd = p->cmd;
  	if (r.cmd != 0xec)
  	if (!rrok(p->h.src)) {
! 		p->h.flags |= Error;
! 		p->h.error = Res;
  		return len;
  	}
! 	if (atacmd(&r, (uchar *)(p+1), maxscnt*512, pktlen - sizeof(*p)) < 0) {
! 		p->h.flags |= Error;
! 		p->h.error = BadArg;
  		return len;
  	}
! 	if (!(p->aflag & Write))
! 	if ((n = p->sectors)) {
  		n -= r.sectors;
  		len = sizeof (Ata) + (n*512);
  	}
! 	p->sectors = r.sectors;
! 	p->err = r.err;
! 	p->cmd = r.status;
  	return len;
  }
  
--- 107,129 ----
  	r.cmd = p->cmd;
  	if (r.cmd != 0xec)
  	if (!rrok(p->h.src)) {
! 		op->h.flags |= Error;
! 		op->h.error = Res;
  		return len;
  	}
! 	if (atacmd(&r, (uchar *)(p+1), (uchar *)(op+1), pktlen - sizeof(*p)) < 0) {
! 		op->h.flags |= Error;
! 		op->h.error = BadArg;
  		return len;
  	}
! 	if (!(op->aflag & Write))
! 	if ((n = op->sectors)) {
  		n -= r.sectors;
  		len = sizeof (Ata) + (n*512);
  	}
! 	op->sectors = r.sectors;
! 	op->err = r.err;
! 	op->cmd = r.status;
  	return len;
  }
  
***************
*** 122,129 ****
  int
  confcmd(Conf *p, int payload)	// process conf request
  {
! 	int len;
! 
  	len = ntohs(p->len);
  	if (QCMD(p) != Qread)
  	if (len > Nconfig || len > payload)
--- 134,140 ----
  int
  confcmd(Conf *p, int payload)	// process conf request
  {
! 	int len;	
  	len = ntohs(p->len);
  	if (QCMD(p) != Qread)
  	if (len > Nconfig || len > payload)
***************
*** 270,276 ****
  		md = mdi;
  		for (i=0; i<nmasks; i++) {
  			md->res = md->cmd = 0;
! 			memmove(md->mac, &masks[i*6], 6);
  			md++;
  		}
  		mh->merror = 0;
--- 281,287 ----
  		md = mdi;
  		for (i=0; i<nmasks; i++) {
  			md->res = md->cmd = 0;
! 			memcpy(md->mac, &masks[i*6], 6);
  			md++;
  		}
  		mh->merror = 0;
***************
*** 285,340 ****
  }
  
  void
! doaoe(Aoehdr *p, int n)
  {
  	int len;
  
! 	switch (p->cmd) {
  	case ATAcmd:
  		if (n < Natahdr)
  			return;
! 		len = aoeata((Ata*)p, n);
  		break;
  	case Config:
  		if (n < Ncfghdr)
  			return;
! 		len = confcmd((Conf *)p, n);
  		break;
  	case Mask:
  		if (n < Nmaskhdr)
  			return;
! 		len = aoemask((Aoemask *)p, n);
  		break;
  	case Resrel:
  		if (n < Nsrrhdr)
  			return;
! 		len = aoesrr((Aoesrr *)p, n);
  		break;
  	default:
! 		p->error = BadCmd;
! 		p->flags |= Error;
  		len = n;
  		break;
  	}
  	if (len <= 0)
  		return;
! 	memmove(p->dst, p->src, 6);
! 	memmove(p->src, mac, 6);
! 	p->maj = htons(shelf);
! 	p->min = slot;
! 	p->flags |= Resp;
! 	if (putpkt(sfd, (uchar *) p, len) == -1) {
  		perror("write to network");
  		exit(1);
  	}
  }
  
! void
! aoe(void)
  {
  	Aoehdr *p;
  	uchar *buf;
- 	int n, sh;
  	long pagesz;
  	enum { bufsz = 1<<16, };
  
--- 296,478 ----
  }
  
  void
! doaoe(Aoehdr *p, Aoehdr *op, int n)
  {
  	int len;
+ 	const uchar cmd = p->cmd;
+ 	memcpy(op->dst, p->src, 6);
+ 	memcpy(op->src, mac, 6);
+ 	op->maj = shelf_net;
+ 	op->min = slot;
+ 
+ 	if (p!=op)
+ 	{
+ 		op->type = p->type;
+ 		op->flags = p->flags | Resp;
+ 		op->error = p->error;
+ 		op->cmd = cmd;
+ 		memcpy(op->tag, p->tag, sizeof(op->tag));
+ 		memcpy(op+1, p+1, (cmd!=ATAcmd)  ? 
+ 			n - sizeof(Aoehdr) : sizeof(Ata) - sizeof(Aoehdr));
+ 	}
+ 	else
+ 		op->flags|= Resp;
  
! 	switch (cmd) {
  	case ATAcmd:
  		if (n < Natahdr)
  			return;
! 		len = aoeata((Ata*)p, (Ata*)op, n);
  		break;
  	case Config:
  		if (n < Ncfghdr)
  			return;
! 		len = confcmd((Conf *)op, n);
  		break;
  	case Mask:
  		if (n < Nmaskhdr)
  			return;
! 		len = aoemask((Aoemask *)op, n);
  		break;
  	case Resrel:
  		if (n < Nsrrhdr)
  			return;
! 		len = aoesrr((Aoesrr *)op, n);
  		break;
  	default:
! 		op->error = BadCmd;
! 		op->flags |= Error;
  		len = n;
  		break;
  	}
  	if (len <= 0)
  		return;
! 	if (putpkt(sfd, (uchar *) op, len) == -1) {
  		perror("write to network");
  		exit(1);
  	}
+ 	if (cmd==ATAcmd) ata_after_party();
  }
  
! 
! 
! #ifdef USE_RX_RING
! static int rxring_offset = 0;
! static int rxring_frames = 0;
! static int rxring_frame_size = 0;
! 
! /// Initialize a packet socket ring buffer
! //  @param ringtype is one of PACKET_RX_RING or PACKET_TX_RING
! static char * init_packetsock_ring(int fd, int ringtype)
! {
! 	struct tpacket_req tp;
! 	char *ring;
! 	rxring_frame_size = PAGE_ALIGN(getmtu(fd, ifname) + TPACKET_ALIGN(sizeof(struct tpacket_hdr)) + TPACKET_ALIGN(sizeof(struct sockaddr_ll)) + 32); 
! 	
! 
! 	//sometimes system fails to allocate neccessary ring space
! 	//try to allocate smaller one in such case
! 	for (rxring_frames = Z_ALIGN(bufcnt, 8);; rxring_frames-= 8)
! 	{
! 		tp.tp_block_size = rxring_frames * rxring_frame_size;
! 		tp.tp_block_nr = 1;
! 		tp.tp_frame_size = rxring_frame_size;
! 		tp.tp_frame_nr = rxring_frames;
! 		if (setsockopt(fd, SOL_PACKET, ringtype, (void*) &tp, sizeof(tp))==0) 
! 			break;
! 
! 		if (rxring_frames<16)
! 		{
! 			perror("setsockopt() ring");
! 			return 0;
! 		}
! 	}
! 
! 	ring = mmap(0, tp.tp_block_size * tp.tp_block_nr, 
! 		PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
! 	if (!ring)
! 	{
! 		perror("mmap() ring");
! 		return 0;
! 	}
! 	printf("initialized RING with %u block (%u frames * %u bytes per frame)\n", tp.tp_block_size, rxring_frames, rxring_frame_size);
! 	return ring;
! }
! 
! 
! static int deinit_packetsock_ring(int fd, char *ring)
! {
! 	 if (munmap(ring, rxring_frames * rxring_frame_size)) {
! 		perror("munmap() ring");
! 		return 1;
! 	}
! 
! 	 return 0;
! }
! 
! /// Blocking read, returns a single packet (from packet ring)
! static void * process_rx(const int fd, char *rx_ring, int *plen)
! {
! 	for (;;)
! 	{
! 		struct tpacket_hdr *header = (void *) rx_ring + (rxring_offset * rxring_frame_size);
! 
! 		while (!(header->tp_status & TP_STATUS_USER)) 
! 		{
! 			struct pollfd pollset;
! 			int ret;
! 
! 			pollset.fd = fd;
! 			pollset.events = POLLIN;
! 			pollset.revents = 0;
! 			int idle_hint = ata_idle_hint();
! 			ret = poll(&pollset, 1, idle_hint);
! 			if (ret==0 && idle_hint!=-1) 
! 			{
! 				ata_idle(idle_hint);
! 				ret = poll(&pollset, 1, -1);
! 			}
! 
! 			if (ret < 0) 
! 			{
! 				if (errno == EINTR)
! 				{
! 					usleep(10000);
! 					continue;
! 				}
! 				perror("poll()");
! 			        return NULL;
! 			}
! 		}
! 
! 		if ((header->tp_status & TP_STATUS_COPY) ==0 )
! 		{
! 			*plen = header->tp_snaplen;
! 			return ((void *) header) + header->tp_mac;
! 		}
! 		//printf("Truncated packet detected: %u, %u\n", header->tp_snaplen, header->tp_len);
! 		header->tp_status = 0;
! 		if ( (++rxring_offset)>=rxring_frames) rxring_offset = 0;
! 	}
! }
! 
! // Release the slot back to the kernel
! static void process_rx_release(char *rx_ring)
! {
! 	struct tpacket_hdr * header = (void *) rx_ring + (rxring_offset * rxring_frame_size);
! 	header->tp_status = 0;
! 	if ( (++rxring_offset)>=rxring_frames) rxring_offset = 0;
! }
! #endif
! 
! 
! void aoe(void)
  {
  	Aoehdr *p;
+ 	int n;
+ 	printf("page size=%u\n", PAGE_ALIGN(1));
+ 
  	uchar *buf;
  	long pagesz;
  	enum { bufsz = 1<<16, };
  
***************
*** 342,379 ****
  		perror("sysconf");
  		exit(1);
  	}        
! 	if ((buf = malloc(bufsz + pagesz)) == NULL) {
! 		perror("malloc");
  		exit(1);
- 	}
- 	n = (size_t) buf + sizeof(Ata);
- 	if (n & (pagesz - 1))
- 		buf += pagesz - (n & (pagesz - 1));
  
  	aoead(sfd);
  
! 	for (;;) {
  		n = getpkt(sfd, buf, bufsz);
  		if (n < 0) {
  			perror("read network");
  			exit(1);
  		}
  		if (n < sizeof(Aoehdr))
  			continue;
! 		p = (Aoehdr *) buf;
! 		if (ntohs(p->type) != 0x88a2)
  			continue;
  		if (p->flags & Resp)
  			continue;
! 		sh = ntohs(p->maj);
! 		if (sh != shelf && sh != (ushort)~0)
  			continue;
  		if (p->min != slot && p->min != (uchar)~0)
  			continue;
  		if (nmasks && !maskok(p->src))
  			continue;
! 		doaoe(p, n);
  	}
  }
  
  void
--- 480,536 ----
  		perror("sysconf");
  		exit(1);
  	}        
!         if ((buf = malloc(bufsz + pagesz)) == NULL) {
!                 perror("malloc");
!                 exit(1);
!         }
!         n = (size_t) buf + sizeof(Ata);
!         if (n & (pagesz - 1))
!                 buf += pagesz - (n & (pagesz - 1));
! 
! 
! #ifdef USE_RX_RING
! 	char * rx_ring = init_packetsock_ring(sfd, PACKET_RX_RING);
! 	if (!rx_ring) 
  		exit(1);
  
  	aoead(sfd);
  
! 	for (;;process_rx_release(rx_ring))  
! 	{
! 		p = (Aoehdr *) process_rx(sfd, rx_ring, &n);
! 		if (!p) break;
! #else
! 
! 	aoead(sfd);
! 
! 	for (;;) 
! 	{
  		n = getpkt(sfd, buf, bufsz);
  		if (n < 0) {
  			perror("read network");
  			exit(1);
  		}
+ 		p = (Aoehdr *) buf;
+ #endif
  		if (n < sizeof(Aoehdr))
  			continue;
! 		if (p->type != type_net)
  			continue;
  		if (p->flags & Resp)
  			continue;
! 		if (p->maj != shelf_net && p->maj != (ushort)~0)
  			continue;
  		if (p->min != slot && p->min != (uchar)~0)
  			continue;
  		if (nmasks && !maskok(p->src))
  			continue;
! 
! 		doaoe(p, (Aoehdr *)buf, n);
  	}
+ #ifdef USE_RX_RING
+ 	deinit_packetsock_ring(sfd, rx_ring);
+ #endif
  }
  
  void
***************
*** 461,467 ****
  int
  main(int argc, char **argv)
  {
! 	int ch, omode = 0, readonly = 0;
  
  	bufcnt = Bufcount;
  	setbuf(stdin, NULL);
--- 618,624 ----
  int
  main(int argc, char **argv)
  {
! 	int ch, omode = O_NOATIME, readonly = 0;
  
  	bufcnt = Bufcount;
  	setbuf(stdin, NULL);
***************
*** 501,506 ****
--- 658,665 ----
  		exit(1);
  	}
  	shelf = atoi(argv[0]);
+ 	shelf_net = htons(shelf);
+ 	type_net = htons(0x88a2);
  	slot = atoi(argv[1]);
  	setserial(argv[3], shelf, slot);
  	size = getsize(bfd);
***************
*** 513,518 ****
--- 672,678 ----
  		readonly ? "O_RDONLY" : "O_RDWR");
  	fflush(stdout);
  	atainit();
+ 	malloc_trim(0);
  	aoe();
  	return 0;
  }
diff -c -r vblade-21/ata.c vblade-21-patched/ata.c
*** vblade-21/ata.c	Thu May  2 18:18:44 2013
--- vblade-21-patched/ata.c	Sun May 11 01:31:12 2014
***************
*** 2,11 ****
--- 2,21 ----
  #include "config.h"
  #include <string.h>
  #include <stdio.h>
+ #include <stdlib.h>
+ #include <unistd.h>
+ #include <malloc.h> 
  #include <sys/types.h>
  #include "dat.h"
  #include "fns.h"
  
+ #define BUFFERS_COUNT		6       //up to 255
+ #define BUFFERED_SECTORS	1024	//maximum numbers of sectors that single buffer can hold
+ #define AFTER_PARTY_SECTORS	1008	//flush buffer that contains so many sectors just after ATA command reply send
+ //#define KEEP_STATS 		//keep detailed buffering statistics and print it out on long idle
+ #define SECTOR_SIZE		512 	//set in stone, dont change
+ 
+ 
  enum {
  	// err bits
  	UNC =	1<<6,
***************
*** 25,30 ****
--- 35,78 ----
  
  static ushort ident[256];
  
+ 
+ 
+ static unsigned long bufs_used_cnt = 0;
+ static struct SectorBuffer
+ {
+     vlong		lba;
+     unsigned long	nsec;
+     unsigned long	used;
+     uchar		*data;    
+ } sbs[BUFFERS_COUNT];
+ 
+ #ifdef KEEP_STATS
+ static struct 
+ {
+ 	vlong  wr_preempt;
+ 	vlong  wr_collide;
+ 	vlong  wr_nice;
+ 	vlong  wr_new;
+ 
+ 	vlong  rd_nice;
+ 	vlong  rd_collide;
+ 	vlong  rd_miss;
+ 
+ 	vlong after_party;
+ } sbst;
+ 
+ # define INIT_STATS do {memset(&sbst, 0, sizeof(sbst)); }while(0);
+ # define INCREMENT_STAT(x) do {++sbst.x;}while(0);
+ # define PRINT_STATS	do {printf("wr_nice=%llu wr_new=%llu wr_preempt=%llu wr_collide=%llu rd_nice=%llu rd_miss=%llu rd_collide=%llu after_party=%llu\n", \
+ 				sbst.wr_nice, sbst.wr_new, sbst.wr_preempt, sbst.wr_collide, sbst.rd_nice, sbst.rd_miss, sbst.rd_collide, sbst.after_party); }while (0);
+ 
+ 
+ #else
+ # define INIT_STATS ;
+ # define INCREMENT_STAT(x) ;
+ # define PRINT_STATS ;
+ #endif
+ 
  static void
  setfld(ushort *a, int idx, int len, char *str)	// set field in ident
  {
***************
*** 98,103 ****
--- 146,154 ----
  	sprintf(buf, "V%d", VBLADE_VERSION);
  	setfld(ident, 23, 8, buf);
  	setfld(ident, 10, 20, serial);
+ 
+ 	memset(&sbs, 0, sizeof(sbs));
+ 	INIT_STATS;
  }
  
  
***************
*** 106,113 ****
   * with LBA 28 you shouldn't see an LBA of all ones.  Still, we don't
   * check for that.
   */
  int
! atacmd(Ataregs *p, uchar *dp, int ndp, int payload) // do the ata cmd
  {
  	vlong lba;
  	ushort *ip;
--- 157,374 ----
   * with LBA 28 you shouldn't see an LBA of all ones.  Still, we don't
   * check for that.
   */
+ 
+ static int flush_sb(struct SectorBuffer *sb)
+ {
+ 	if (putsec(bfd, &sb->data[0], sb->lba, sb->nsec)!=(sb->nsec*SECTOR_SIZE))
+ 		return -1;
+ 
+ 	sb->nsec = 0; 
+ 	sb->lba = 0;
+ 	sb->used = 0; 
+ 	return 0;
+ }
+ 
+ int ata_idle_hint()
+ {
+ 	unsigned char has_data = 0, i;
+ 	for (i = 0; i< BUFFERS_COUNT; ++i)
+ 	{
+ 		if (sbs[i].data)
+ 		{
+ 			if (sbs[i].lba)
+ 				return 1000;
+ 
+ 			has_data = 1;
+ 		}
+ 	}
+ 
+ 	return has_data ? 10000 : -1;
+ }
+ 
+ void ata_idle(int t)
+ {
+ 	unsigned char frd = 0, i;
+ 	for (i = 0; i< BUFFERS_COUNT; ++i)
+ 	{
+ 		if (sbs[i].data)
+ 		{
+ 			if (sbs[i].lba) flush_sb(&sbs[i]);
+ 			if (t>=10000) 
+ 			{
+ 				free(sbs[i].data);
+ 				sbs[i].data = 0;
+ 				frd = 1;
+ 			}
+ 		}
+ 	}
+ 
+ 	if (frd)
+ 	{
+ 		malloc_trim(0);
+ 		printf("ATA: free'd cache buffer\n");		
+ 		PRINT_STATS;
+ 	}
+ }
+ 
+ static unsigned char wanna_after_party = 0;
+ 
+ void ata_after_party()
+ {
+ 	if (wanna_after_party)
+ 	{
+ 		wanna_after_party = 0;
+ 		struct SectorBuffer *oldest_sb = 0;
+ 		uchar i, flush_oldest_sb = 1;
+ 		for (i = 0; i<BUFFERS_COUNT; ++i)
+ 		{
+ 			struct SectorBuffer *sbc = &sbs[i];
+ 			if (sbc->nsec>=AFTER_PARTY_SECTORS)
+ 			{
+ 				if (flush_sb(sbc)==0)
+ 				{
+ 					INCREMENT_STAT(after_party);
+ 					flush_oldest_sb = 0;
+ 				}
+ 			}
+ 			else if (sbc->lba)
+ 			{
+ 				if (!oldest_sb || oldest_sb->used>sbc->used)
+ 					oldest_sb = sbc;
+ 			}
+ 			else
+ 				flush_oldest_sb = 0;
+ 		}
+ 		if (flush_oldest_sb && oldest_sb) 
+ 		{
+ 			if (flush_sb(oldest_sb)==0)
+ 				INCREMENT_STAT(after_party);
+ 		}
+ 	}
+ }
+ 
+ static inline char are_regions_overlap(vlong lba1, int nsec1, vlong lba2, int nsec2)
+ {	
+ 	return (lba1<(lba2+nsec2) && lba2<(lba1+nsec1));
+ }
+ 
+ static int bfd_putsec(uchar *place, vlong lba, int nsec)
+ {
+ //return putsec(bfd, place, lba, nsec);
+ 	struct SectorBuffer *sb = 0;
+ 	unsigned char nice = 0, i;
+ 	wanna_after_party = 1;
+ 	for (i = 0; i<BUFFERS_COUNT; ++i)
+ 	{
+ 		struct SectorBuffer *sbc = &sbs[i];
+ 		if (sbc->lba)
+ 		{
+ 			if (!nice && sbc->lba<=lba && (sbc->lba+sbc->nsec)>=lba && (lba + (vlong)nsec - sbc->lba)<=BUFFERED_SECTORS)
+ 			{
+ 				sb = sbc;				
+ 				nice = 1;
+ 			}
+ 			else if (are_regions_overlap(lba, nsec, sbc->lba, sbc->nsec))
+ 			{				
+ 				INCREMENT_STAT(wr_collide);
+ 				flush_sb(sbc);
+ 				if (!nice) sb = sbc;
+ 			}
+ 			else if (!sb || (!nice && sbc->used<sb->used))
+ 			{
+ 				sb = sbc;
+ 			}
+ 		}
+ 		else if (!sb)
+ 		{
+ 			sb = sbc;
+ 		}
+ 		else if (!nice && sbc->used<sb->used)
+ 		{
+ 			if (!sb->lba)
+ 				wanna_after_party = 0;
+ 			else
+ 				sb = sbc;
+ 		}
+ 		else
+ 			wanna_after_party = 0;
+ 	}
+ 		
+ 
+ 	if (sb)
+ 	{
+ 		if (!nice)
+ 		{
+ 			if (sb->lba) 
+ 			{
+ 				if (flush_sb(sb)==0)
+ 					INCREMENT_STAT(wr_preempt)
+ 				else
+ 					sb = 0;
+ 			}
+ 			else
+ 				INCREMENT_STAT(wr_new);
+ 
+ 			if (sb)
+ 			{
+ 				if (!sb->data)
+ 				{
+ 					sb->data = valloc(BUFFERED_SECTORS*SECTOR_SIZE);
+ 					printf("Allocated buffer\n");
+ 				}
+ 				if (sb->data)
+ 					sb->lba = lba;
+ 				else
+ 					sb  = 0;
+ 			}
+ 		}
+ 		else
+ 			INCREMENT_STAT(wr_nice);
+ 
+ 		if (sb)
+ 		{
+ 		        vlong til_nsec =  lba + (vlong)nsec - sb->lba;
+ 		        nsec*= SECTOR_SIZE;
+ 		        memcpy(&sb->data[(lba - sb->lba)*SECTOR_SIZE], place, nsec);
+ 		        if (sb->nsec<til_nsec) sb->nsec = til_nsec;
+ 			sb->used = ++bufs_used_cnt;
+ 		        return nsec;
+ 		}
+ 	}
+ 
+ 	return putsec(bfd, place, lba, nsec);
+ }
+ 
+ static int bfd_getsec(uchar *place, vlong lba, int nsec)
+ {
+ //return getsec(bfd, place, lba, nsec);
+ 	unsigned char i;
+ 	for (i = 0; i<BUFFERS_COUNT; ++i)
+ 	{
+ 		struct SectorBuffer *sb = &sbs[i];
+ 		if (sb->lba && are_regions_overlap(lba, nsec, sb->lba, sb->nsec))
+ 		{
+ 			if (lba>=sb->lba && (lba+(vlong)nsec)<=(sb->lba+sb->nsec))
+ 			{
+ 				nsec*= SECTOR_SIZE;
+ 				memcpy(place, &sb->data[(lba - sb->lba)*SECTOR_SIZE], nsec);
+ 				sb->used = ++bufs_used_cnt;
+ 				INCREMENT_STAT(rd_nice);
+ 				return nsec;
+ 			}
+ 
+         		if (flush_sb(sb)!=0)
+             			return -1;
+ 			INCREMENT_STAT(rd_collide);
+ 		}
+ 	}
+ 	INCREMENT_STAT(rd_miss);
+ 
+ 	return getsec(bfd, place, lba, nsec);
+ }
+ 
  int
! atacmd(Ataregs *p, uchar *dp, uchar *odp, int payload) // do the ata cmd
  {
  	vlong lba;
  	ushort *ip;
***************
*** 124,133 ****
  	case 0xe7:		// flush cache
  		return 0;
  	case 0xec:		// identify device
! 		if (p->sectors != 1 || ndp < 512)
  			return -1;
! 		memmove(dp, ident, 512);
! 		ip = (ushort *)dp;
  		if (size & ~MAXLBA28SIZE)
  			setlba28(ip, MAXLBA28SIZE);
  		else
--- 385,394 ----
  	case 0xe7:		// flush cache
  		return 0;
  	case 0xec:		// identify device
! 		if (p->sectors != 1 || maxscnt<1)
  			return -1;
! 		memcpy(odp, ident, 512);
! 		ip = (ushort *)odp;
  		if (size & ~MAXLBA28SIZE)
  			setlba28(ip, MAXLBA28SIZE);
  		else
***************
*** 142,161 ****
  		p->sectors = 0xff; // the device is active or idle
  		p->status = DRDY;
  		return 0;
! 	case 0x20:		// read sectors
  	case 0x30:		// write sectors
  		lba = p->lba & MAXLBA28SIZE;
  		break;
! 	case 0x24:		// read sectors ext
  	case 0x34:		// write sectors ext
  		lba = p->lba & 0x0000ffffffffffffLL;	// full 48
  		break;
  	}
  
  	// we ought not be here unless we are a read/write
  
- 	if (p->sectors > maxscnt || p->sectors*512 > ndp)
- 		return -1;
  
  	if (lba + p->sectors > size) {
  		p->err = IDNF;
--- 403,422 ----
  		p->sectors = 0xff; // the device is active or idle
  		p->status = DRDY;
  		return 0;
! 
  	case 0x30:		// write sectors
+ 	case 0x20:		// read sectors
  		lba = p->lba & MAXLBA28SIZE;
  		break;
! 
  	case 0x34:		// write sectors ext
+ 	case 0x24:		// read sectors ext
  		lba = p->lba & 0x0000ffffffffffffLL;	// full 48
  		break;
  	}
  
  	// we ought not be here unless we are a read/write
  
  
  	if (lba + p->sectors > size) {
  		p->err = IDNF;
***************
*** 163,175 ****
  		p->lba = lba;
  		return 0;
  	}
! 	if (p->cmd == 0x20 || p->cmd == 0x24)
! 		n = getsec(bfd, dp, lba, p->sectors);
! 	else {
  		// packet should be big enough to contain the data
  		if (payload < 512 * p->sectors)
  			return -1;
! 		n = putsec(bfd, dp, lba, p->sectors);
  	}
  	n /= 512;
  	if (n != p->sectors) {
--- 424,438 ----
  		p->lba = lba;
  		return 0;
  	}
! 	if (p->cmd == 0x20 || p->cmd == 0x24) {
! 		if (maxscnt < p->sectors)
! 			return -1;
! 		n = bfd_getsec(odp, lba, p->sectors);
! 	} else {
  		// packet should be big enough to contain the data
  		if (payload < 512 * p->sectors)
  			return -1;
! 		n = bfd_putsec(dp, lba, p->sectors);
  	}
  	n /= 512;
  	if (n != p->sectors) {
diff -c -r vblade-21/dat.h vblade-21-patched/dat.h
*** vblade-21/dat.h	Thu May  2 18:18:44 2013
--- vblade-21-patched/dat.h	Sat May 10 19:47:03 2014
***************
*** 20,25 ****
--- 20,29 ----
  #define	minor(x)		((x) & 0xffffff)
  #define	makedev(x, y)	((x) << 24 | (y))
  
+ #define Z_ALIGN(x, z)        (((x)+(z)-1)&~((z)-1))
+ #define PAGE_ALIGN(x)        Z_ALIGN(x, getpagesize())
+ 
+ 
  typedef unsigned char uchar;
  //typedef unsigned short ushort;
  #ifdef __FreeBSD__
***************
*** 164,169 ****
--- 168,174 ----
  };
  
  int	shelf, slot;
+ ushort  shelf_net, type_net;
  ulong	aoetag;
  uchar	mac[6];
  int	bfd;		// block file descriptor
diff -c -r vblade-21/fns.h vblade-21-patched/fns.h
*** vblade-21/fns.h	Fri Aug 14 20:42:44 2009
--- vblade-21-patched/fns.h	Sat May 10 21:09:24 2014
***************
*** 16,22 ****
  // ata.c
  
  void	atainit(void);
! int	atacmd(Ataregs *, uchar *, int, int);
  
  // bpf.c
  
--- 16,26 ----
  // ata.c
  
  void	atainit(void);
! int	atacmd(Ataregs *, uchar *, uchar *, int);
! int	ata_idle_hint();
! void	ata_idle(int t);
! void	ata_after_party();
! 
  
  // bpf.c
  
diff -c -r vblade-21/linux.c vblade-21-patched/linux.c
*** vblade-21/linux.c	Thu Oct  9 00:07:40 2008
--- vblade-21-patched/linux.c	Sat May 10 19:19:40 2014
***************
*** 38,54 ****
  {
  	int i, n, s;
  	struct sockaddr_ll sa;
- 	enum { aoe_type = 0x88a2 };
  
  	memset(&sa, 0, sizeof sa);
! 	s = socket(PF_PACKET, SOCK_RAW, htons(aoe_type));
  	if (s == -1) {
  		perror("got bad socket");
  		return -1;
  	}
  	i = getindx(s, eth);
  	sa.sll_family = AF_PACKET;
! 	sa.sll_protocol = htons(0x88a2);
  	sa.sll_ifindex = i;
  	n = bind(s, (struct sockaddr *)&sa, sizeof sa);
  	if (n == -1) {
--- 38,53 ----
  {
  	int i, n, s;
  	struct sockaddr_ll sa;
  
  	memset(&sa, 0, sizeof sa);
! 	s = socket(PF_PACKET, SOCK_RAW, type_net);
  	if (s == -1) {
  		perror("got bad socket");
  		return -1;
  	}
  	i = getindx(s, eth);
  	sa.sll_family = AF_PACKET;
! 	sa.sll_protocol = type_net;
  	sa.sll_ifindex = i;
  	n = bind(s, (struct sockaddr *)&sa, sizeof sa);
  	if (n == -1) {
***************
*** 63,74 ****
  	setsockopt(s, SOL_SOCKET, SO_ATTACH_FILTER, bpf_program, sizeof(*bpf_program));
  	free_bpf_program(bpf_program);
  
! 	n = bufcnt * getmtu(s, eth);
  	if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, &n, sizeof(n)) < 0)
  		perror("setsockopt SOL_SOCKET, SO_SNDBUF");
  	if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, &n, sizeof(n)) < 0)
  		perror("setsockopt SOL_SOCKET, SO_RCVBUF");
! 
  	return s;
  }
  
--- 62,76 ----
  	setsockopt(s, SOL_SOCKET, SO_ATTACH_FILTER, bpf_program, sizeof(*bpf_program));
  	free_bpf_program(bpf_program);
  
! 	n = getmtu(s, eth);
!         printf("MTU=%u\n", n);
!         n*= bufcnt;
  	if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, &n, sizeof(n)) < 0)
  		perror("setsockopt SOL_SOCKET, SO_SNDBUF");
+ /*
  	if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, &n, sizeof(n)) < 0)
  		perror("setsockopt SOL_SOCKET, SO_RCVBUF");
! */
  	return s;
  }
  
***************
*** 119,131 ****
  int
  getsec(int fd, uchar *place, vlong lba, int nsec)
  {
! 	return pread(fd, place, nsec * 512, lba * 512);
  }
  
  int
  putsec(int fd, uchar *place, vlong lba, int nsec)
  {
! 	return pwrite(fd, place, nsec * 512, lba * 512);
  }
  
  int
--- 121,137 ----
  int
  getsec(int fd, uchar *place, vlong lba, int nsec)
  {
! 	int n = pread(fd, place, nsec * 512, lba * 512);
! 	if (n!=nsec * 512) perror("getsec failed");
! 	return n;
  }
  
  int
  putsec(int fd, uchar *place, vlong lba, int nsec)
  {
! 	int n = pwrite(fd, place, nsec * 512, lba * 512);
! 	if (n!=nsec * 512) perror("putsec failed");
! 	return n;
  }
  
  int
