152e112b3ab6b2b35a144565c8ea3bdda1e2845f2Ed L. Cashin/* Copyright (c) 2007 Coraid, Inc.  See COPYING for GPL terms. */
28911ef4dc97f77797f297318010a7424300d2d50Ed L. Cashin#define VERSION "47"
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define AOE_MAJOR 152
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DEVICE_NAME "aoe"
5fc458dcda27c6d26cb11ef9ee9c1c3599711be94Ed L. Cashin
6fc458dcda27c6d26cb11ef9ee9c1c3599711be94Ed L. Cashin/* set AOE_PARTITIONS to 1 to use whole-disks only
7fc458dcda27c6d26cb11ef9ee9c1c3599711be94Ed L. Cashin * default is 16, which is 15 partitions plus the whole disk
8fc458dcda27c6d26cb11ef9ee9c1c3599711be94Ed L. Cashin */
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifndef AOE_PARTITIONS
10e39526e6e7a96904c9f1c85375d49ff437c18c44Ed L. Cashin#define AOE_PARTITIONS (16)
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
12fc458dcda27c6d26cb11ef9ee9c1c3599711be94Ed L. Cashin
13e39526e6e7a96904c9f1c85375d49ff437c18c44Ed L. Cashin#define SYSMINOR(aoemajor, aoeminor) ((aoemajor) * NPERSHELF + (aoeminor))
14e39526e6e7a96904c9f1c85375d49ff437c18c44Ed L. Cashin#define AOEMAJOR(sysminor) ((sysminor) / NPERSHELF)
15e39526e6e7a96904c9f1c85375d49ff437c18c44Ed L. Cashin#define AOEMINOR(sysminor) ((sysminor) % NPERSHELF)
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define WHITESPACE " \t\v\f\n"
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsenum {
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	AOECMD_ATA,
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	AOECMD_CFG,
21b6d6c5175809934e04a606d9193ef04924a7a7d9Ed L. Cashin	AOECMD_VEND_MIN = 0xf0,
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	AOEFL_RSP = (1<<3),
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	AOEFL_ERR = (1<<2),
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	AOEAFL_EXT = (1<<6),
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	AOEAFL_DEV = (1<<4),
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	AOEAFL_ASYNC = (1<<1),
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	AOEAFL_WRITE = (1<<0),
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	AOECCMD_READ = 0,
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	AOECCMD_TEST,
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	AOECCMD_PTEST,
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	AOECCMD_SET,
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	AOECCMD_FSET,
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	AOE_HVER = 0x10,
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct aoe_hdr {
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char dst[6];
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char src[6];
4363e9cc5d6fbe8b58ea1ee96439d356cbf726fbc0Ed L. Cashin	__be16 type;
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char verfl;
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char err;
4663e9cc5d6fbe8b58ea1ee96439d356cbf726fbc0Ed L. Cashin	__be16 major;
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char minor;
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char cmd;
4963e9cc5d6fbe8b58ea1ee96439d356cbf726fbc0Ed L. Cashin	__be32 tag;
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct aoe_atahdr {
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char aflags;
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char errfeat;
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char scnt;
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char cmdstat;
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char lba0;
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char lba1;
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char lba2;
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char lba3;
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char lba4;
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char lba5;
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char res[2];
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct aoe_cfghdr {
6763e9cc5d6fbe8b58ea1ee96439d356cbf726fbc0Ed L. Cashin	__be16 bufcnt;
6863e9cc5d6fbe8b58ea1ee96439d356cbf726fbc0Ed L. Cashin	__be16 fwver;
6919bf26353c50bc2be375109ec73f2f0bbd616ed1Ed L. Cashin	unsigned char scnt;
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char aoeccmd;
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char cslen[2];
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsenum {
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DEVFL_UP = 1,	/* device is installed in system and ready for AoE->ATA commands */
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DEVFL_TKILL = (1<<1),	/* flag for timer to know when to kill self */
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DEVFL_EXT = (1<<2),	/* device accepts lba48 commands */
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DEVFL_CLOSEWAIT = (1<<3), /* device is waiting for all closes to revalidate */
793ae1c24e395b2b65326439622223d88d92bfa03aEd L. Cashin	DEVFL_GDALLOC = (1<<4),	/* need to alloc gendisk */
8068e0d42f39d85b334d3867a4e5fc2e0e775c1a6cEd L. Cashin	DEVFL_KICKME = (1<<5),	/* slow polling network card catch */
813ae1c24e395b2b65326439622223d88d92bfa03aEd L. Cashin	DEVFL_NEWSIZE = (1<<6),	/* need to update dev size in block layer */
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	BUFFL_FAIL = 1,
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsenum {
8719bf26353c50bc2be375109ec73f2f0bbd616ed1Ed L. Cashin	DEFAULTBCNT = 2 * 512,	/* 2 sectors */
88e39526e6e7a96904c9f1c85375d49ff437c18c44Ed L. Cashin	NPERSHELF = 16,		/* number of slots per shelf address */
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	FREETAG = -1,
9068e0d42f39d85b334d3867a4e5fc2e0e775c1a6cEd L. Cashin	MIN_BUFS = 16,
9168e0d42f39d85b334d3867a4e5fc2e0e775c1a6cEd L. Cashin	NTARGETS = 8,
9268e0d42f39d85b334d3867a4e5fc2e0e775c1a6cEd L. Cashin	NAOEIFS = 8,
939bb237b6a670fa7a6af3adc65231b1f6fda44510Ed L. Cashin	NSKBPOOLMAX = 128,
9468e0d42f39d85b334d3867a4e5fc2e0e775c1a6cEd L. Cashin
9568e0d42f39d85b334d3867a4e5fc2e0e775c1a6cEd L. Cashin	TIMERTICK = HZ / 10,
9668e0d42f39d85b334d3867a4e5fc2e0e775c1a6cEd L. Cashin	MINTIMER = HZ >> 2,
9768e0d42f39d85b334d3867a4e5fc2e0e775c1a6cEd L. Cashin	MAXTIMER = HZ << 1,
9868e0d42f39d85b334d3867a4e5fc2e0e775c1a6cEd L. Cashin	HELPWAIT = 20,
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct buf {
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct list_head bufs;
10368e0d42f39d85b334d3867a4e5fc2e0e775c1a6cEd L. Cashin	ulong stime;	/* for disk stats */
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ulong flags;
1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ulong nframesout;
1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ulong resid;
1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ulong bv_resid;
10868e0d42f39d85b334d3867a4e5fc2e0e775c1a6cEd L. Cashin	ulong bv_off;
1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sector_t sector;
1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct bio *bio;
1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct bio_vec *bv;
1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct frame {
1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int tag;
1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ulong waited;
1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct buf *buf;
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char *bufaddr;
11919bf26353c50bc2be375109ec73f2f0bbd616ed1Ed L. Cashin	ulong bcnt;
12019bf26353c50bc2be375109ec73f2f0bbd616ed1Ed L. Cashin	sector_t lba;
121e407a7f6cd143b3ab4eb3d7e1cf882e96b710eb5Ed L. Cashin	struct sk_buff *skb;
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12468e0d42f39d85b334d3867a4e5fc2e0e775c1a6cEd L. Cashinstruct aoeif {
12568e0d42f39d85b334d3867a4e5fc2e0e775c1a6cEd L. Cashin	struct net_device *nd;
12668e0d42f39d85b334d3867a4e5fc2e0e775c1a6cEd L. Cashin	unsigned char lost;
12768e0d42f39d85b334d3867a4e5fc2e0e775c1a6cEd L. Cashin	unsigned char lostjumbo;
12868e0d42f39d85b334d3867a4e5fc2e0e775c1a6cEd L. Cashin	ushort maxbcnt;
12968e0d42f39d85b334d3867a4e5fc2e0e775c1a6cEd L. Cashin};
13068e0d42f39d85b334d3867a4e5fc2e0e775c1a6cEd L. Cashin
13168e0d42f39d85b334d3867a4e5fc2e0e775c1a6cEd L. Cashinstruct aoetgt {
13268e0d42f39d85b334d3867a4e5fc2e0e775c1a6cEd L. Cashin	unsigned char addr[6];
13368e0d42f39d85b334d3867a4e5fc2e0e775c1a6cEd L. Cashin	ushort nframes;
13468e0d42f39d85b334d3867a4e5fc2e0e775c1a6cEd L. Cashin	struct frame *frames;
13568e0d42f39d85b334d3867a4e5fc2e0e775c1a6cEd L. Cashin	struct aoeif ifs[NAOEIFS];
13668e0d42f39d85b334d3867a4e5fc2e0e775c1a6cEd L. Cashin	struct aoeif *ifp;	/* current aoeif in use */
13768e0d42f39d85b334d3867a4e5fc2e0e775c1a6cEd L. Cashin	ushort nout;
13868e0d42f39d85b334d3867a4e5fc2e0e775c1a6cEd L. Cashin	ushort maxout;
13968e0d42f39d85b334d3867a4e5fc2e0e775c1a6cEd L. Cashin	u16 lasttag;		/* last tag sent */
14068e0d42f39d85b334d3867a4e5fc2e0e775c1a6cEd L. Cashin	u16 useme;
14168e0d42f39d85b334d3867a4e5fc2e0e775c1a6cEd L. Cashin	ulong lastwadj;		/* last window adjustment */
14268e0d42f39d85b334d3867a4e5fc2e0e775c1a6cEd L. Cashin	int wpkts, rpkts;
1439bb237b6a670fa7a6af3adc65231b1f6fda44510Ed L. Cashin	int dataref;
14468e0d42f39d85b334d3867a4e5fc2e0e775c1a6cEd L. Cashin};
14568e0d42f39d85b334d3867a4e5fc2e0e775c1a6cEd L. Cashin
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct aoedev {
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct aoedev *next;
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ulong sysminor;
1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ulong aoemajor;
15068e0d42f39d85b334d3867a4e5fc2e0e775c1a6cEd L. Cashin	u16 aoeminor;
15168e0d42f39d85b334d3867a4e5fc2e0e775c1a6cEd L. Cashin	u16 flags;
152dced3a053dd5415a7321e1ae153c96dea644da4eEd L. Cashin	u16 nopen;		/* (bd_openers isn't available without sleeping) */
153dced3a053dd5415a7321e1ae153c96dea644da4eEd L. Cashin	u16 rttavg;		/* round trip average of requests/responses */
154dced3a053dd5415a7321e1ae153c96dea644da4eEd L. Cashin	u16 mintimer;
1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16 fw_ver;		/* version of blade's firmware */
1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct work_struct work;/* disk create work struct */
1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct gendisk *gd;
1587135a71b19be1faf48b7148d77844d03bc0717d6Ed L. Cashin	struct request_queue *blkq;
1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct hd_geometry geo;
1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sector_t ssize;
1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct timer_list timer;
1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spinlock_t lock;
163e9bb8fb0b6d61a822201537b25206a0ca34b9d1dDavid S. Miller	struct sk_buff_head sendq;
164e9bb8fb0b6d61a822201537b25206a0ca34b9d1dDavid S. Miller	struct sk_buff_head skbpool;
1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	mempool_t *bufpool;	/* for deadlock-free Buf allocation */
1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct list_head bufq;	/* queue of bios to work on */
1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct buf *inprocess;	/* the one we're currently working on */
16868e0d42f39d85b334d3867a4e5fc2e0e775c1a6cEd L. Cashin	struct aoetgt *targets[NTARGETS];
16968e0d42f39d85b334d3867a4e5fc2e0e775c1a6cEd L. Cashin	struct aoetgt **tgt;	/* target in use when working */
17068e0d42f39d85b334d3867a4e5fc2e0e775c1a6cEd L. Cashin	struct aoetgt **htgt;	/* target needing rexmit assistance */
1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint aoeblk_init(void);
1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid aoeblk_exit(void);
1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid aoeblk_gdalloc(void *);
1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid aoedisk_rm_sysfs(struct aoedev *d);
1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint aoechr_init(void);
1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid aoechr_exit(void);
1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid aoechr_error(char *);
1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid aoecmd_work(struct aoedev *d);
1843ae1c24e395b2b65326439622223d88d92bfa03aEd L. Cashinvoid aoecmd_cfg(ushort aoemajor, unsigned char aoeminor);
1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid aoecmd_ata_rsp(struct sk_buff *);
1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid aoecmd_cfg_rsp(struct sk_buff *);
187c4028958b6ecad064b1a6303a6a5906d4fe48d73David Howellsvoid aoecmd_sleepwork(struct work_struct *);
18868e0d42f39d85b334d3867a4e5fc2e0e775c1a6cEd L. Cashinvoid aoecmd_cleanslate(struct aoedev *);
18968e0d42f39d85b334d3867a4e5fc2e0e775c1a6cEd L. Cashinstruct sk_buff *aoecmd_ata_id(struct aoedev *);
1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint aoedev_init(void);
1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid aoedev_exit(void);
19332465c650670c7499548d70fdeed57fab44ee679Ed L. Cashinstruct aoedev *aoedev_by_aoeaddr(int maj, int min);
19468e0d42f39d85b334d3867a4e5fc2e0e775c1a6cEd L. Cashinstruct aoedev *aoedev_by_sysminor_m(ulong sysminor);
1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid aoedev_downdev(struct aoedev *d);
196262bf54144ebcb78cd0d057d2705dc5fb7bba7acEd L. Cashinint aoedev_flush(const char __user *str, size_t size);
1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint aoenet_init(void);
1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid aoenet_exit(void);
200e9bb8fb0b6d61a822201537b25206a0ca34b9d1dDavid S. Millervoid aoenet_xmit(struct sk_buff_head *);
2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint is_aoe_netif(struct net_device *ifp);
2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint set_aoe_iflist(const char __user *str, size_t size);
2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
204