Browse Source

Import upstream version 10

Ed L. Cashin 14 years ago
parent
commit
08559d90e9
14 changed files with 428 additions and 17 deletions
  1. 29 0
      NEWS
  2. 6 1
      README
  3. 18 9
      aoe.c
  4. 6 1
      ata.c
  5. 0 1
      config.h
  6. 2 0
      config/config.h.in
  7. 8 0
      config/u64.c
  8. 8 1
      dat.h
  9. 2 0
      fns.h
  10. 315 0
      freebsd.c
  11. 12 0
      linux.c
  12. 21 3
      makefile
  13. BIN
      vblade
  14. 1 1
      vbladed

+ 29 - 0
NEWS

@@ -1,4 +1,33 @@
 -*- change-log -*-
+
+2005-12-06 Ed L. Cashin <ecashin@coraid.com>
+	fix u64 configuration on FreeBSD
+	release vblade-10
+	
+2005-12-06 Valeriy Glushkov <valery@rocketdivision.com>
+	implemented config string support
+	added handler for ATA Check power mode command
+	
+2005-11-15 Ed L. Cashin <ecashin@coraid.com>
+	add compatibility with platforms lacking u64 (e.g., Slackware)
+	release vblade-9
+	
+2005-11-10 Ed L. Cashin <ecashin@coraid.com>
+	call atainit on program startup
+	put VBLADE_VERSION in dat.h and use it in firmware version
+	release vblade-7
+	include Stacey's patch to use p{read,write} on FreeBSD
+	include Stacey's patch to typedef ulong on FreeBSD
+	fix makefile dependencies (e.g., rebuild on new aoe.c)
+	fix config string length specification
+	include Stacey's patch to avoid compile warnings on FreeBSD
+	release vblade-8
+	
+2005-11-10 "Stacey D. Son" <sson@verio.net>
+	include FreeBSD support
+	
+2005-10-03 Ed L. Cashin <ecashin@coraid.com>
+	don't invoke vblade with dash from vbladed
 	
 2005-08-31 20:14:12 GMT Ed L. Cashin <ecashin@coraid.com>
 	ATA identify: don't juggle bytes in shorts on big endian arch

+ 6 - 1
README

@@ -12,10 +12,15 @@ The Linux aoe driver for the 2.6 kernel is compatible if you use
 aoe-2.6-7 or newer.  You can use older aoe drivers but you will only
 be able to see one vblade per MAC address.
 
-The following command should build the vblade program:
+The following command should build the vblade program on a Linux-based
+system:
 
   make
 
+For FreeBSD systems, include an extra parameter like so:
+
+  make PLATFORM=freebsd
+
 There is a "vbladed" script that daemonizes the program and sends its
 output to the logger program.  Make sure you have logger installed if
 you would like to run vblade as a daemon with the vbladed script.

+ 18 - 9
aoe.c

@@ -10,17 +10,25 @@
 #include "dat.h"
 #include "fns.h"
 
-// dummy for testing
+char cfg_str[1024];
+int cfg_str_len = 0;
+
 int
 qcget(uchar *p, int len)
 {
-	memset(p, 0xff, len);
+	if (len > cfg_str_len)
+		len = cfg_str_len;
+	memcpy(p, cfg_str, len);
 	return len;
 }
 
 int
 qcset(uchar *p, int len)
 {
+	if (len > sizeof(cfg_str))
+		len = sizeof(cfg_str);
+	memcpy(cfg_str, p, len);
+	cfg_str_len = len;
 	return len;
 }
 
@@ -45,8 +53,8 @@ aoead(int fd)			// advertise the virtual blade
 	p->vercmd = 0x10 | Qread;
 	len = qcget(p->data, 1024);
 	p->len = htons(len);
-	if (write(fd, buf, len) == -1)
-		perror("write aoe id");
+	if (putpkt(fd, buf, sizeof *p - sizeof p->data + len) == -1)
+		perror("putpkt aoe id");
 }
 
 int
@@ -118,12 +126,12 @@ confcmd(Conf *p)	// process conf request
 		p->len = htons(len);
 		break;
 	case Qset:
-		if (qcget(buf, 1024) > 0) {
+		len = qcget(buf, 1024);
+		if (len > 0 && (len != p->len || memcmp(buf, p->data, len))) {
 			p->h.flags |= Error;
 			p->h.error = ConfigErr;
 			break;
 		}
-		len = 1024;
 		// fall thru
 	case Qfset:
 		len = ntohs(p->len);
@@ -135,7 +143,7 @@ confcmd(Conf *p)	// process conf request
 	p->bufcnt = htons(Bufcount);
 	p->firmware = htons(FWV);
 	p->vercmd |= 0x10;
-	return len;
+	return len + sizeof(Conf) - 1024;
 }
 
 void
@@ -161,7 +169,7 @@ doaoe(Aoehdr *p)
 	p->maj = htons(shelf);
 	p->min = slot;
 	p->flags |= Resp;
-	if (write(sfd, p, len) == -1) {
+	if (putpkt(sfd, (uchar *) p, len) == -1) {
 		perror("write to network");
 		exit(1);
 	}
@@ -177,7 +185,7 @@ aoe(void)
 	aoead(sfd);
 
 	for (;;) {
-		n = read(sfd, buf, sizeof buf);
+		n = getpkt(sfd, buf, sizeof buf);
 		if (n < 0) {
 			perror("read network");
 			exit(1);
@@ -210,6 +218,7 @@ int
 main(int argc, char **argv)
 {
 	setbuf(stdin, NULL);
+	atainit();
 	progname = *argv;
 	if (argc != 5)
 		usage();

+ 6 - 1
ata.c

@@ -86,7 +86,7 @@ atainit(void)
 	char buf[64];
 
 	setfld(ident, 27, 40, "Coraid EtherDrive vblade");
-	sprintf(buf, "V%d.%d\n", 4, 0);
+	sprintf(buf, "V%d\n", VBLADE_VERSION);
 	setfld(ident, 23, 8, buf);
 	setfld(ident, 10, 20, "SSN HERE");
 }
@@ -127,6 +127,11 @@ atacmd(Ataregs *p, uchar *dp)		// do the ata cmd
 		p->err = 0;
 		p->status = DRDY;
 		return;
+	case 0xe5:		// check power mode
+		p->err = 0;
+		p->sectors = 0xff; // the device is active or idle
+		p->status = DRDY;
+		return;
 	default:
 		p->status = DRDY | ERR;
 		p->err = ABRT;

+ 0 - 1
config.h

@@ -1 +0,0 @@
-#define _FILE_OFFSET_BITS 64 

+ 2 - 0
config/config.h.in

@@ -0,0 +1,2 @@
+#define _FILE_OFFSET_BITS 64 
+//u64 typedef unsigned long long u64;

+ 8 - 0
config/u64.c

@@ -0,0 +1,8 @@
+#include <stdio.h>
+
+int main(void)
+{
+	u64 n;
+	printf("%d\n", (int) n+2);
+	return 0;
+}

+ 8 - 1
dat.h

@@ -6,7 +6,10 @@
  */
 
 enum {
-	FWV			= 0x4000,		// Firmware version
+	VBLADE_VERSION		= 10,
+
+	// Firmware version
+	FWV			= 0x4000 + VBLADE_VERSION,
 };
 
 #undef major
@@ -19,7 +22,11 @@ enum {
 
 typedef unsigned char uchar;
 //typedef unsigned short ushort;
+#ifdef __FreeBSD__
+typedef unsigned long ulong;
+#else
 //typedef unsigned long ulong;
+#endif
 typedef long long vlong;
 
 typedef struct Aoehdr Aoehdr;

+ 2 - 0
fns.h

@@ -22,4 +22,6 @@ int	dial(char *);
 int	getea(int, char *, uchar *);
 int	putsec(int, uchar *, vlong, int);
 int	getsec(int, uchar *, vlong, int);
+int	putpkt(int, uchar *, int);
+int	getpkt(int, uchar *, int);
 vlong	getsize(int);

+ 315 - 0
freebsd.c

@@ -0,0 +1,315 @@
+/*
+ * Copyright (c) 2005, Stacey Son <sson (at) verio (dot) net>
+ * All rights reserved.
+ */
+
+// freebsd.c: low level access routines for FreeBSD
+#include "config.h"
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/time.h>
+
+#include <netinet/in.h>
+#include <net/ethernet.h>
+#include <net/bpf.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <net/if_dl.h>
+#include <net/route.h>
+
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <net/if.h>
+#include <sys/stat.h>
+#include <sys/disklabel.h>
+#include <sys/select.h>
+#include <sys/sysctl.h>
+
+#include <fcntl.h>
+#include <errno.h>
+
+#include "dat.h"
+#include "fns.h"
+
+#define BPF_DEV "/dev/bpf0"
+
+/* Packet buffer for getpkt() */
+static uchar *pktbuf = NULL;
+static int pktbufsz = 0;
+
+int
+dial(char *eth)
+{
+	char m;
+	int fd = -1;
+	struct bpf_version bv;
+	u_int v;
+	unsigned bufsize, linktype;
+	char device[sizeof BPF_DEV];
+	struct ifreq ifr;
+
+	/* packet filter for bpf */
+	struct bpf_insn bpf_insns[] = {
+	  /* Load the type into register */
+	  BPF_STMT(BPF_LD+BPF_H+BPF_ABS, 12),
+	  /* Does it match AoE Type (0x88a2)? No, goto INVALID */
+	  BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0x88a2, 0, 10),
+	  /* Load the flags into register */
+	  BPF_STMT(BPF_LD+BPF_B+BPF_ABS, 14),
+	  /* Check to see if the Resp flag is set */
+	  BPF_STMT(BPF_ALU+BPF_AND+BPF_K, Resp),
+	  /* Yes, goto INVALID */
+	  BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0, 0, 7),
+	  /* Load the command into register */
+	  BPF_STMT(BPF_LD+BPF_B+BPF_ABS, 19),
+	  /* Is this a ATAcmd? No, goto VALID */
+	  BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, ATAcmd, 0, 4),
+	  /* Load the shelf number into register */
+	  BPF_STMT(BPF_LD+BPF_H+BPF_ABS, 16),
+	  /* Does it match shelf number? No, goto INVALID */
+	  BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (u_int) shelf, 0, 3),
+	  /* Load the slot number into register */
+	  BPF_STMT(BPF_LD+BPF_B+BPF_ABS, 18),
+	  /* Does it match shelf number? No, goto INVALID */
+	  BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, (u_int) slot, 0, 1),
+	  /* VALID: return -1 (allow the packet to be read) */
+	  BPF_STMT(BPF_RET+BPF_K, (u_int)-1),
+	  /* INVALID: return 0 (ignore the packet) */
+	  BPF_STMT(BPF_RET+BPF_K, 0),
+	};
+
+	struct bpf_program bpf_program = {
+	  sizeof(bpf_insns)/sizeof(struct bpf_insn),
+	  bpf_insns
+	};
+
+
+	strncpy(device, BPF_DEV, sizeof BPF_DEV);
+
+	/* find a bpf device we can use, check /dev/bpf[0-9] */
+	for (m = '0'; m <= '9'; m++) {
+		device[sizeof(BPF_DEV)-2] = m;
+
+		if ((fd = open(device, O_RDWR)) > 0)
+			break;
+	}
+
+	if (fd < 0) {
+		perror("open");
+		return -1;
+	}
+
+	if (ioctl(fd, BIOCVERSION, &bv) < 0) {
+		perror("BIOCVERSION");
+		goto bad;
+	}
+
+	if (bv.bv_major != BPF_MAJOR_VERSION ||
+	    bv.bv_minor < BPF_MINOR_VERSION) {
+		fprintf(stderr,
+			"kernel bpf filter out of date\n");
+		goto bad;
+	}
+
+	/*
+	 * Try finding a good size for the buffer; 65536 may be too
+	 * big, so keep cutting it in half until we find a size
+	 * that works, or run out of sizes to try.
+	 *
+	 */
+	for (v = 65536; v != 0; v >>= 1) {
+		(void) ioctl(fd, BIOCSBLEN, (caddr_t)&v);
+
+		(void)strncpy(ifr.ifr_name, eth,
+			sizeof(ifr.ifr_name));
+		if (ioctl(fd, BIOCSETIF, (caddr_t)&ifr) >= 0)
+			break;  /* that size worked; we're done */
+
+		if (errno != ENOBUFS) {
+			fprintf(stderr, "BIOCSETIF: %s: %s\n",
+					eth, strerror(errno));
+			goto bad;
+		}
+	}
+	if (v == 0) {
+		fprintf(stderr, 
+			"BIOCSBLEN: %s: No buffer size worked\n", eth);
+		goto bad;
+	}
+
+	/* Allocate memory for the packet buffer */
+	pktbufsz = v;
+	if ((pktbuf = malloc(pktbufsz)) == NULL) {
+		perror("malloc");
+		goto bad;
+	}
+
+	/* Don't wait for buffer to be full or timeout */
+	v = 1;
+	if (ioctl(fd, BIOCIMMEDIATE, &v) < 0) {
+		perror("BIOCIMMEDIATE");
+		goto bad;
+	}
+
+	/* Only read incoming packets */
+	v = 0;
+	if (ioctl(fd, BIOCSSEESENT, &v) < 0) {
+		perror("BIOCSSEESENT");
+		goto bad;
+	}
+
+	/* Don't complete ethernet hdr */
+	v = 1;
+	if (ioctl(fd, BIOCSHDRCMPLT, &v) < 0) {
+		perror("BIOCSHDRCMPLT");
+		goto bad;
+	}
+
+	/* Get the data link layer type. */
+	if (ioctl(fd, BIOCGDLT, (caddr_t)&v) < 0) {
+		perror("BIOCGDLT");
+		goto bad;
+	}
+	linktype = v;
+
+	/* Get the filter buf size */
+	if (ioctl(fd, BIOCGBLEN, (caddr_t)&v) < 0) {
+		perror("BIOCGBLEN");
+		goto bad;
+	}
+	bufsize = v;
+
+	if (ioctl(fd, BIOCSETF, (caddr_t)&bpf_program) < 0) {
+		perror("BIOSETF");
+		goto bad;
+	} 
+
+	return(fd);
+
+bad:
+	close(fd);
+	return(-1);
+}
+
+int
+getea(int s, char *eth, uchar *ea)
+{
+	int mib[6];
+	size_t len;
+	char *buf, *next, *end;
+	struct if_msghdr *ifm;
+	struct sockaddr_dl *sdl;
+	
+
+	mib[0] = CTL_NET; 	mib[1] = AF_ROUTE;
+	mib[2] = 0; 		mib[3] = AF_LINK;
+	mib[4] = NET_RT_IFLIST;	mib[5] = 0;
+
+	if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0) {
+		return (-1);
+	}
+
+	if (!(buf = (char *) malloc(len))) {
+		return (-1);
+	}
+	
+	if (sysctl(mib, 6, buf, &len, NULL, 0) < 0) {
+		free(buf);
+		return (-1);
+	}
+	end = buf + len;
+
+	for (next = buf; next < end; next += ifm->ifm_msglen) {
+		ifm = (struct if_msghdr *)next;
+		if (ifm->ifm_type == RTM_IFINFO) {
+			sdl = (struct sockaddr_dl *)(ifm + 1);
+			if (strncmp(&sdl->sdl_data[0], eth, 
+					sdl->sdl_nlen) == 0) {
+				memcpy(ea, LLADDR(sdl), ETHER_ADDR_LEN);
+				break;
+			}
+
+		}
+
+	}
+
+	free(buf);
+	return(0);
+}
+
+
+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);
+}
+
+static int pktn = 0;
+static uchar *pktbp = NULL;
+
+int
+getpkt(int fd, uchar *buf, int sz)
+{
+	register struct bpf_hdr *bh;
+	register int pktlen, retlen;
+	
+	if (pktn <= 0) { 
+		if ((pktn = read(fd, pktbuf, pktbufsz)) < 0) {
+			perror("read");
+			exit(1);
+		}
+		pktbp = pktbuf;
+	}
+
+	bh = (struct bpf_hdr *) pktbp;
+	retlen = (int) bh->bh_caplen;
+	/* This memcpy() is currently needed */ 
+	memcpy(buf, (void *)(pktbp + bh->bh_hdrlen),
+		retlen > sz ? sz : retlen);
+	pktlen = bh->bh_hdrlen + bh->bh_caplen; 
+	
+	pktbp = pktbp + BPF_WORDALIGN(pktlen);
+	pktn  -= (int) BPF_WORDALIGN(pktlen);
+
+	return retlen; 
+}
+
+int
+putpkt(int fd, uchar *buf, int sz)
+{
+	return write(fd, buf, sz);
+}
+
+vlong
+getsize(int fd)
+{
+	vlong size;
+	struct stat s;
+	int n;
+	struct disklabel lab;
+
+	// Try getting disklabel from block dev
+	if ((n = ioctl(fd, DIOCGDINFO, lab)) != -1) {  
+		size = lab.d_secsize * lab.d_secperunit;
+	} else {
+		// must not be a block special dev
+		if (fstat(fd, &s) == -1) {
+			perror("getsize");
+			exit(1);
+		}
+		size = s.st_size;
+	}
+	printf("ioctl returned %d\n", n);
+	printf("%lld bytes\n", size);
+	return size;
+}

+ 12 - 0
linux.c

@@ -100,6 +100,18 @@ putsec(int fd, uchar *place, vlong lba, int nsec)
 	return write(fd, place, nsec * 512);
 }
 
+int
+getpkt(int fd, uchar *buf, int sz)
+{
+	return read(fd, buf, sz);
+}
+
+int
+putpkt(int fd, uchar *buf, int sz)
+{
+	return write(fd, buf, sz);
+}
+
 vlong
 getsize(int fd)
 {

+ 21 - 3
makefile

@@ -1,12 +1,30 @@
 # makefile for vblade
 
-O=aoe.o linux.o ata.o
+# see README for others
+PLATFORM=linux
+
+O=aoe.o ${PLATFORM}.o ata.o
 CFLAGS += -Wall -g -O2
+CC = gcc
 
 vblade: $O
-	cc -o vblade $O
+	${CC} -o vblade $O
+
+aoe.o : aoe.c config.h dat.h fns.h makefile
+	${CC} ${CFLAGS} -c $<
+
+${PLATFORM}.o : ${PLATFORM}.c config.h dat.h fns.h makefile
+	${CC} ${CFLAGS} -c $<
+
+ata.o : ata.c config.h dat.h fns.h makefile
+	${CC} ${CFLAGS} -c $<
 
-$O: dat.h fns.h
+config.h : config/config.h.in makefile
+	@if ${CC} ${CFLAGS} config/u64.c > /dev/null 2>&1; then \
+	  sh -xc "cp config/config.h.in config.h"; \
+	else \
+	  sh -xc "sed 's!^//u64 !!' config/config.h.in > config.h"; \
+	fi
 
 clean :
 	rm -f $O vblade

BIN
vblade


+ 1 - 1
vbladed

@@ -3,4 +3,4 @@
 # output is directed to syslogd
 #
 
-sh -c "`dirname $0`/vblade - $* < /dev/null 2>&1 | logger -t vbladed" &
+sh -c "`dirname $0`/vblade $* < /dev/null 2>&1 | logger -t vbladed" &