fwmem.c revision 139749
1139749Simp/*-
2113584Ssimokawa * Copyright (c) 2002-2003
3103285Sikob * 	Hidetoshi Shimokawa. All rights reserved.
4103285Sikob *
5103285Sikob * Redistribution and use in source and binary forms, with or without
6103285Sikob * modification, are permitted provided that the following conditions
7103285Sikob * are met:
8103285Sikob * 1. Redistributions of source code must retain the above copyright
9103285Sikob *    notice, this list of conditions and the following disclaimer.
10103285Sikob * 2. Redistributions in binary form must reproduce the above copyright
11103285Sikob *    notice, this list of conditions and the following disclaimer in the
12103285Sikob *    documentation and/or other materials provided with the distribution.
13103285Sikob * 3. All advertising materials mentioning features or use of this software
14103285Sikob *    must display the following acknowledgement:
15103285Sikob *
16103285Sikob *	This product includes software developed by Hidetoshi Shimokawa.
17103285Sikob *
18103285Sikob * 4. Neither the name of the author nor the names of its contributors
19103285Sikob *    may be used to endorse or promote products derived from this software
20103285Sikob *    without specific prior written permission.
21103285Sikob *
22103285Sikob * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23103285Sikob * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24103285Sikob * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25103285Sikob * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26103285Sikob * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27103285Sikob * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28103285Sikob * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29103285Sikob * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30103285Sikob * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31103285Sikob * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32103285Sikob * SUCH DAMAGE.
33103285Sikob *
34103285Sikob */
35103285Sikob
36127468Ssimokawa#ifdef __FreeBSD__
37119418Sobrien#include <sys/cdefs.h>
38119418Sobrien__FBSDID("$FreeBSD: head/sys/dev/firewire/fwmem.c 139749 2005-01-06 01:43:34Z imp $");
39127468Ssimokawa#endif
40119418Sobrien
41103285Sikob#include <sys/param.h>
42103285Sikob#include <sys/systm.h>
43103285Sikob#include <sys/types.h>
44103285Sikob
45103285Sikob#include <sys/kernel.h>
46103285Sikob#include <sys/malloc.h>
47103285Sikob#include <sys/conf.h>
48103285Sikob#include <sys/sysctl.h>
49127468Ssimokawa#if defined(__DragonFly__) || __FreeBSD_version < 500000
50120660Ssimokawa#include <sys/buf.h>
51120660Ssimokawa#else
52120660Ssimokawa#include <sys/bio.h>
53120660Ssimokawa#endif
54103285Sikob
55103285Sikob#include <sys/bus.h>
56113584Ssimokawa#include <machine/bus.h>
57103285Sikob
58103285Sikob#include <sys/signal.h>
59103285Sikob#include <sys/mman.h>
60103285Sikob#include <sys/ioccom.h>
61122228Ssimokawa#include <sys/fcntl.h>
62103285Sikob
63127468Ssimokawa#ifdef __DragonFly__
64127468Ssimokawa#include "firewire.h"
65127468Ssimokawa#include "firewirereg.h"
66127468Ssimokawa#include "fwmem.h"
67127468Ssimokawa#else
68103285Sikob#include <dev/firewire/firewire.h>
69103285Sikob#include <dev/firewire/firewirereg.h>
70103285Sikob#include <dev/firewire/fwmem.h>
71127468Ssimokawa#endif
72103285Sikob
73106810Ssimokawastatic int fwmem_speed=2, fwmem_debug=0;
74106810Ssimokawastatic struct fw_eui64 fwmem_eui64;
75103285SikobSYSCTL_DECL(_hw_firewire);
76103285SikobSYSCTL_NODE(_hw_firewire, OID_AUTO, fwmem, CTLFLAG_RD, 0,
77108281Ssimokawa	"FireWire Memory Access");
78106810SsimokawaSYSCTL_UINT(_hw_firewire_fwmem, OID_AUTO, eui64_hi, CTLFLAG_RW,
79106810Ssimokawa	&fwmem_eui64.hi, 0, "Fwmem target EUI64 high");
80110582SsimokawaSYSCTL_UINT(_hw_firewire_fwmem, OID_AUTO, eui64_lo, CTLFLAG_RW,
81106810Ssimokawa	&fwmem_eui64.lo, 0, "Fwmem target EUI64 low");
82103285SikobSYSCTL_INT(_hw_firewire_fwmem, OID_AUTO, speed, CTLFLAG_RW, &fwmem_speed, 0,
83103285Sikob	"Fwmem link speed");
84103285SikobSYSCTL_INT(_debug, OID_AUTO, fwmem_debug, CTLFLAG_RW, &fwmem_debug, 0,
85103285Sikob	"Fwmem driver debug flag");
86103285Sikob
87124145SsimokawaMALLOC_DEFINE(M_FWMEM, "fwmem", "fwmem/FireWire");
88124145Ssimokawa
89120660Ssimokawa#define MAXLEN (512 << fwmem_speed)
90120660Ssimokawa
91122228Ssimokawastruct fwmem_softc {
92122228Ssimokawa	struct fw_eui64 eui;
93122228Ssimokawa	int refcount;
94122228Ssimokawa};
95122228Ssimokawa
96106816Ssimokawastatic struct fw_xfer *
97106816Ssimokawafwmem_xfer_req(
98106810Ssimokawa	struct fw_device *fwdev,
99106816Ssimokawa	caddr_t sc,
100106816Ssimokawa	int spd,
101113584Ssimokawa	int slen,
102113584Ssimokawa	int rlen,
103106816Ssimokawa	void *hand)
104103285Sikob{
105103285Sikob	struct fw_xfer *xfer;
106103285Sikob
107124145Ssimokawa	xfer = fw_xfer_alloc(M_FWMEM);
108106804Ssimokawa	if (xfer == NULL)
109103285Sikob		return NULL;
110106804Ssimokawa
111106810Ssimokawa	xfer->fc = fwdev->fc;
112120660Ssimokawa	xfer->send.hdr.mode.hdr.dst = FWLOCALBUS | fwdev->dst;
113106816Ssimokawa	if (spd < 0)
114120660Ssimokawa		xfer->send.spd = fwdev->speed;
115106816Ssimokawa	else
116120660Ssimokawa		xfer->send.spd = min(spd, fwdev->speed);
117106804Ssimokawa	xfer->act.hand = hand;
118103285Sikob	xfer->retry_req = fw_asybusy;
119106816Ssimokawa	xfer->sc = sc;
120120660Ssimokawa	xfer->send.pay_len = slen;
121120660Ssimokawa	xfer->recv.pay_len = rlen;
122103285Sikob
123106816Ssimokawa	return xfer;
124106816Ssimokawa}
125106816Ssimokawa
126106816Ssimokawastruct fw_xfer *
127106816Ssimokawafwmem_read_quad(
128106816Ssimokawa	struct fw_device *fwdev,
129106816Ssimokawa	caddr_t	sc,
130129585Sdfr	uint8_t spd,
131129585Sdfr	uint16_t dst_hi,
132129585Sdfr	uint32_t dst_lo,
133120660Ssimokawa	void *data,
134106816Ssimokawa	void (*hand)(struct fw_xfer *))
135106816Ssimokawa{
136106816Ssimokawa	struct fw_xfer *xfer;
137106816Ssimokawa	struct fw_pkt *fp;
138106816Ssimokawa
139120660Ssimokawa	xfer = fwmem_xfer_req(fwdev, (void *)sc, spd, 0, 4, hand);
140120660Ssimokawa	if (xfer == NULL) {
141106816Ssimokawa		return NULL;
142120660Ssimokawa	}
143106816Ssimokawa
144120660Ssimokawa	fp = &xfer->send.hdr;
145103285Sikob	fp->mode.rreqq.tcode = FWTCODE_RREQQ;
146113584Ssimokawa	fp->mode.rreqq.dest_hi = dst_hi;
147113584Ssimokawa	fp->mode.rreqq.dest_lo = dst_lo;
148103285Sikob
149120660Ssimokawa	xfer->send.payload = NULL;
150129585Sdfr	xfer->recv.payload = (uint32_t *)data;
151120660Ssimokawa
152103285Sikob	if (fwmem_debug)
153106816Ssimokawa		printf("fwmem_read_quad: %d %04x:%08x\n", fwdev->dst,
154106816Ssimokawa				dst_hi, dst_lo);
155106804Ssimokawa
156106810Ssimokawa	if (fw_asyreq(xfer->fc, -1, xfer) == 0)
157103285Sikob		return xfer;
158106804Ssimokawa
159103285Sikob	fw_xfer_free(xfer);
160103285Sikob	return NULL;
161103285Sikob}
162103285Sikob
163103285Sikobstruct fw_xfer *
164106810Ssimokawafwmem_write_quad(
165106810Ssimokawa	struct fw_device *fwdev,
166106810Ssimokawa	caddr_t	sc,
167129585Sdfr	uint8_t spd,
168129585Sdfr	uint16_t dst_hi,
169129585Sdfr	uint32_t dst_lo,
170120660Ssimokawa	void *data,
171106810Ssimokawa	void (*hand)(struct fw_xfer *))
172106810Ssimokawa{
173106810Ssimokawa	struct fw_xfer *xfer;
174106810Ssimokawa	struct fw_pkt *fp;
175106810Ssimokawa
176120660Ssimokawa	xfer = fwmem_xfer_req(fwdev, sc, spd, 0, 0, hand);
177106810Ssimokawa	if (xfer == NULL)
178106810Ssimokawa		return NULL;
179106810Ssimokawa
180120660Ssimokawa	fp = &xfer->send.hdr;
181110072Ssimokawa	fp->mode.wreqq.tcode = FWTCODE_WREQQ;
182113584Ssimokawa	fp->mode.wreqq.dest_hi = dst_hi;
183113584Ssimokawa	fp->mode.wreqq.dest_lo = dst_lo;
184129585Sdfr	fp->mode.wreqq.data = *(uint32_t *)data;
185106810Ssimokawa
186120660Ssimokawa	xfer->send.payload = xfer->recv.payload = NULL;
187106810Ssimokawa
188106810Ssimokawa	if (fwmem_debug)
189106816Ssimokawa		printf("fwmem_write_quad: %d %04x:%08x %08x\n", fwdev->dst,
190129585Sdfr			dst_hi, dst_lo, *(uint32_t *)data);
191106810Ssimokawa
192106810Ssimokawa	if (fw_asyreq(xfer->fc, -1, xfer) == 0)
193106810Ssimokawa		return xfer;
194106810Ssimokawa
195106810Ssimokawa	fw_xfer_free(xfer);
196106810Ssimokawa	return NULL;
197106810Ssimokawa}
198106810Ssimokawa
199106810Ssimokawastruct fw_xfer *
200103285Sikobfwmem_read_block(
201106810Ssimokawa	struct fw_device *fwdev,
202106810Ssimokawa	caddr_t	sc,
203129585Sdfr	uint8_t spd,
204129585Sdfr	uint16_t dst_hi,
205129585Sdfr	uint32_t dst_lo,
206106804Ssimokawa	int len,
207120660Ssimokawa	void *data,
208106804Ssimokawa	void (*hand)(struct fw_xfer *))
209103285Sikob{
210103285Sikob	struct fw_xfer *xfer;
211103285Sikob	struct fw_pkt *fp;
212120660Ssimokawa
213120660Ssimokawa	xfer = fwmem_xfer_req(fwdev, sc, spd, 0, roundup2(len, 4), hand);
214106804Ssimokawa	if (xfer == NULL)
215103285Sikob		return NULL;
216106804Ssimokawa
217120660Ssimokawa	fp = &xfer->send.hdr;
218103285Sikob	fp->mode.rreqb.tcode = FWTCODE_RREQB;
219113584Ssimokawa	fp->mode.rreqb.dest_hi = dst_hi;
220113584Ssimokawa	fp->mode.rreqb.dest_lo = dst_lo;
221113584Ssimokawa	fp->mode.rreqb.len = len;
222120660Ssimokawa	fp->mode.rreqb.extcode = 0;
223103285Sikob
224120660Ssimokawa	xfer->send.payload = NULL;
225120660Ssimokawa	xfer->recv.payload = data;
226120660Ssimokawa
227103285Sikob	if (fwmem_debug)
228106816Ssimokawa		printf("fwmem_read_block: %d %04x:%08x %d\n", fwdev->dst,
229106810Ssimokawa				dst_hi, dst_lo, len);
230106810Ssimokawa	if (fw_asyreq(xfer->fc, -1, xfer) == 0)
231103285Sikob		return xfer;
232106804Ssimokawa
233103285Sikob	fw_xfer_free(xfer);
234103285Sikob	return NULL;
235103285Sikob}
236103285Sikob
237110337Ssimokawastruct fw_xfer *
238110337Ssimokawafwmem_write_block(
239110337Ssimokawa	struct fw_device *fwdev,
240110337Ssimokawa	caddr_t	sc,
241129585Sdfr	uint8_t spd,
242129585Sdfr	uint16_t dst_hi,
243129585Sdfr	uint32_t dst_lo,
244110337Ssimokawa	int len,
245120660Ssimokawa	void *data,
246110337Ssimokawa	void (*hand)(struct fw_xfer *))
247110337Ssimokawa{
248110337Ssimokawa	struct fw_xfer *xfer;
249110337Ssimokawa	struct fw_pkt *fp;
250110337Ssimokawa
251120660Ssimokawa	xfer = fwmem_xfer_req(fwdev, sc, spd, len, 0, hand);
252110337Ssimokawa	if (xfer == NULL)
253110337Ssimokawa		return NULL;
254110337Ssimokawa
255120660Ssimokawa	fp = &xfer->send.hdr;
256110406Ssimokawa	fp->mode.wreqb.tcode = FWTCODE_WREQB;
257113584Ssimokawa	fp->mode.wreqb.dest_hi = dst_hi;
258113584Ssimokawa	fp->mode.wreqb.dest_lo = dst_lo;
259113584Ssimokawa	fp->mode.wreqb.len = len;
260120660Ssimokawa	fp->mode.wreqb.extcode = 0;
261110337Ssimokawa
262120660Ssimokawa	xfer->send.payload = data;
263120660Ssimokawa	xfer->recv.payload = NULL;
264120660Ssimokawa
265110337Ssimokawa	if (fwmem_debug)
266110337Ssimokawa		printf("fwmem_write_block: %d %04x:%08x %d\n", fwdev->dst,
267110337Ssimokawa				dst_hi, dst_lo, len);
268110337Ssimokawa	if (fw_asyreq(xfer->fc, -1, xfer) == 0)
269110337Ssimokawa		return xfer;
270110337Ssimokawa
271110337Ssimokawa	fw_xfer_free(xfer);
272110337Ssimokawa	return NULL;
273110337Ssimokawa}
274110337Ssimokawa
275110337Ssimokawa
276103285Sikobint
277130585Sphkfwmem_open (struct cdev *dev, int flags, int fmt, fw_proc *td)
278103285Sikob{
279122228Ssimokawa	struct fwmem_softc *fms;
280110582Ssimokawa
281122228Ssimokawa	if (dev->si_drv1 != NULL) {
282122228Ssimokawa		if ((flags & FWRITE) != 0)
283122228Ssimokawa			return (EBUSY);
284122228Ssimokawa		fms = (struct fwmem_softc *)dev->si_drv1;
285122228Ssimokawa		fms->refcount ++;
286122228Ssimokawa	} else {
287122228Ssimokawa		fms = (struct fwmem_softc *)malloc(sizeof(struct fwmem_softc),
288124145Ssimokawa							M_FWMEM, M_WAITOK);
289122228Ssimokawa		if (fms == NULL)
290122228Ssimokawa			return ENOMEM;
291122228Ssimokawa		bcopy(&fwmem_eui64, &fms->eui, sizeof(struct fw_eui64));
292122228Ssimokawa		dev->si_drv1 = (void *)fms;
293122228Ssimokawa		dev->si_iosize_max = DFLTPHYS;
294122228Ssimokawa		fms->refcount = 1;
295122228Ssimokawa	}
296122228Ssimokawa	if (fwmem_debug)
297127468Ssimokawa		printf("%s: refcount=%d\n", __func__, fms->refcount);
298110582Ssimokawa
299110582Ssimokawa	return (0);
300103285Sikob}
301103285Sikob
302103285Sikobint
303130585Sphkfwmem_close (struct cdev *dev, int flags, int fmt, fw_proc *td)
304103285Sikob{
305122228Ssimokawa	struct fwmem_softc *fms;
306115786Ssimokawa
307122228Ssimokawa	fms = (struct fwmem_softc *)dev->si_drv1;
308122228Ssimokawa	fms->refcount --;
309122228Ssimokawa	if (fwmem_debug)
310127468Ssimokawa		printf("%s: refcount=%d\n", __func__, fms->refcount);
311122228Ssimokawa	if (fms->refcount < 1) {
312137503Ssimokawa		free(dev->si_drv1, M_FWMEM);
313122228Ssimokawa		dev->si_drv1 = NULL;
314122228Ssimokawa	}
315122228Ssimokawa
316110582Ssimokawa	return (0);
317103285Sikob}
318103285Sikob
319120660Ssimokawa
320120660Ssimokawastatic void
321120660Ssimokawafwmem_biodone(struct fw_xfer *xfer)
322103285Sikob{
323120660Ssimokawa	struct bio *bp;
324103285Sikob
325120660Ssimokawa	bp = (struct bio *)xfer->sc;
326120660Ssimokawa	bp->bio_error = xfer->resp;
327120660Ssimokawa
328120660Ssimokawa	if (bp->bio_error != 0) {
329121381Ssimokawa		if (fwmem_debug)
330127468Ssimokawa			printf("%s: err=%d\n", __func__, bp->bio_error);
331120660Ssimokawa		bp->bio_flags |= BIO_ERROR;
332120660Ssimokawa		bp->bio_resid = bp->bio_bcount;
333106810Ssimokawa	}
334103285Sikob
335120660Ssimokawa	fw_xfer_free(xfer);
336120660Ssimokawa	biodone(bp);
337103285Sikob}
338120660Ssimokawa
339120660Ssimokawavoid
340120660Ssimokawafwmem_strategy(struct bio *bp)
341103285Sikob{
342110337Ssimokawa	struct firewire_softc *sc;
343122228Ssimokawa	struct fwmem_softc *fms;
344110337Ssimokawa	struct fw_device *fwdev;
345110337Ssimokawa	struct fw_xfer *xfer;
346130585Sphk	struct cdev *dev;
347120660Ssimokawa	int unit, err=0, s, iolen;
348110337Ssimokawa
349120660Ssimokawa	dev = bp->bio_dev;
350120660Ssimokawa	/* XXX check request length */
351120660Ssimokawa
352120660Ssimokawa        unit = DEV2UNIT(dev);
353110337Ssimokawa	sc = devclass_get_softc(firewire_devclass, unit);
354120660Ssimokawa
355120660Ssimokawa	s = splfw();
356122228Ssimokawa	fms = (struct fwmem_softc *)dev->si_drv1;
357122228Ssimokawa	fwdev = fw_noderesolve_eui64(sc->fc, &fms->eui);
358110337Ssimokawa	if (fwdev == NULL) {
359110577Ssimokawa		if (fwmem_debug)
360110577Ssimokawa			printf("fwmem: no such device ID:%08x%08x\n",
361122228Ssimokawa					fms->eui.hi, fms->eui.lo);
362120660Ssimokawa		err = EINVAL;
363120660Ssimokawa		goto error;
364110337Ssimokawa	}
365110337Ssimokawa
366120660Ssimokawa	iolen = MIN(bp->bio_bcount, MAXLEN);
367120660Ssimokawa	if ((bp->bio_cmd & BIO_READ) == BIO_READ) {
368120660Ssimokawa		if (iolen == 4 && (bp->bio_offset & 3) == 0)
369120660Ssimokawa			xfer = fwmem_read_quad(fwdev,
370120660Ssimokawa			    (void *) bp, fwmem_speed,
371120660Ssimokawa			    bp->bio_offset >> 32, bp->bio_offset & 0xffffffff,
372120660Ssimokawa			    bp->bio_data, fwmem_biodone);
373120660Ssimokawa		else
374120660Ssimokawa			xfer = fwmem_read_block(fwdev,
375120660Ssimokawa			    (void *) bp, fwmem_speed,
376120660Ssimokawa			    bp->bio_offset >> 32, bp->bio_offset & 0xffffffff,
377120660Ssimokawa			    iolen, bp->bio_data, fwmem_biodone);
378120660Ssimokawa	} else {
379120660Ssimokawa		if (iolen == 4 && (bp->bio_offset & 3) == 0)
380120660Ssimokawa			xfer = fwmem_write_quad(fwdev,
381120660Ssimokawa			    (void *)bp, fwmem_speed,
382120660Ssimokawa			    bp->bio_offset >> 32, bp->bio_offset & 0xffffffff,
383120660Ssimokawa			    bp->bio_data, fwmem_biodone);
384120660Ssimokawa		else
385120660Ssimokawa			xfer = fwmem_write_block(fwdev,
386120660Ssimokawa			    (void *)bp, fwmem_speed,
387120660Ssimokawa			    bp->bio_offset >> 32, bp->bio_offset & 0xffffffff,
388120660Ssimokawa			    iolen, bp->bio_data, fwmem_biodone);
389110337Ssimokawa	}
390120660Ssimokawa	if (xfer == NULL) {
391120660Ssimokawa		err = EIO;
392120660Ssimokawa		goto error;
393120660Ssimokawa	}
394120660Ssimokawa	/* XXX */
395120660Ssimokawa	bp->bio_resid = bp->bio_bcount - iolen;
396120660Ssimokawaerror:
397120660Ssimokawa	splx(s);
398120660Ssimokawa	if (err != 0) {
399121381Ssimokawa		if (fwmem_debug)
400127468Ssimokawa			printf("%s: err=%d\n", __func__, err);
401120660Ssimokawa		bp->bio_error = err;
402120660Ssimokawa		bp->bio_flags |= BIO_ERROR;
403120660Ssimokawa		bp->bio_resid = bp->bio_bcount;
404120660Ssimokawa		biodone(bp);
405120660Ssimokawa	}
406103285Sikob}
407110337Ssimokawa
408103285Sikobint
409130585Sphkfwmem_ioctl (struct cdev *dev, u_long cmd, caddr_t data, int flag, fw_proc *td)
410103285Sikob{
411122228Ssimokawa	struct fwmem_softc *fms;
412110582Ssimokawa	int err = 0;
413122228Ssimokawa
414122228Ssimokawa	fms = (struct fwmem_softc *)dev->si_drv1;
415110582Ssimokawa	switch (cmd) {
416110582Ssimokawa	case FW_SDEUI64:
417122228Ssimokawa		bcopy(data, &fms->eui, sizeof(struct fw_eui64));
418110582Ssimokawa		break;
419110582Ssimokawa	case FW_GDEUI64:
420122228Ssimokawa		bcopy(&fms->eui, data, sizeof(struct fw_eui64));
421110582Ssimokawa		break;
422110582Ssimokawa	default:
423110582Ssimokawa		err = EINVAL;
424110582Ssimokawa	}
425110582Ssimokawa	return(err);
426103285Sikob}
427103285Sikobint
428130585Sphkfwmem_poll (struct cdev *dev, int events, fw_proc *td)
429103285Sikob{
430103285Sikob	return EINVAL;
431103285Sikob}
432103285Sikobint
433127468Ssimokawa#if defined(__DragonFly__) || __FreeBSD_version < 500102
434130585Sphkfwmem_mmap (struct cdev *dev, vm_offset_t offset, int nproto)
435111615Ssimokawa#else
436130585Sphkfwmem_mmap (struct cdev *dev, vm_offset_t offset, vm_paddr_t *paddr, int nproto)
437111615Ssimokawa#endif
438103285Sikob{
439103285Sikob	return EINVAL;
440103285Sikob}
441