1/*	$NetBSD: dpti.c,v 1.43 2010/11/13 13:51:59 uebayasi Exp $	*/
2
3/*-
4 * Copyright (c) 2001, 2007 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Andrew Doran.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 *    notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32/*
33 * Copyright (c) 1996-2000 Distributed Processing Technology Corporation
34 * Copyright (c) 2000 Adaptec Corporation
35 * All rights reserved.
36 *
37 * TERMS AND CONDITIONS OF USE
38 *
39 * Redistribution and use in source form, with or without modification, are
40 * permitted provided that redistributions of source code must retain the
41 * above copyright notice, this list of conditions and the following disclaimer.
42 *
43 * This software is provided `as is' by Adaptec and any express or implied
44 * warranties, including, but not limited to, the implied warranties of
45 * merchantability and fitness for a particular purpose, are disclaimed. In no
46 * event shall Adaptec be liable for any direct, indirect, incidental, special,
47 * exemplary or consequential damages (including, but not limited to,
48 * procurement of substitute goods or services; loss of use, data, or profits;
49 * or business interruptions) however caused and on any theory of liability,
50 * whether in contract, strict liability, or tort (including negligence or
51 * otherwise) arising in any way out of the use of this driver software, even
52 * if advised of the possibility of such damage.
53 */
54
55/*
56 * Adaptec/DPT I2O control interface.
57 */
58
59#include <sys/cdefs.h>
60__KERNEL_RCSID(0, "$NetBSD: dpti.c,v 1.43 2010/11/13 13:51:59 uebayasi Exp $");
61
62#include <sys/param.h>
63#include <sys/systm.h>
64#include <sys/kernel.h>
65#include <sys/device.h>
66#include <sys/queue.h>
67#include <sys/proc.h>
68#include <sys/endian.h>
69#include <sys/malloc.h>
70#include <sys/conf.h>
71#include <sys/ioctl.h>
72#include <sys/kauth.h>
73
74#include <sys/bus.h>
75#ifdef __i386__
76#include <machine/pio.h>
77#include <machine/cputypes.h>
78#endif
79
80#include <dev/i2o/i2o.h>
81#include <dev/i2o/i2odpt.h>
82#include <dev/i2o/iopio.h>
83#include <dev/i2o/iopvar.h>
84#include <dev/i2o/dptivar.h>
85
86#ifdef I2ODEBUG
87#define	DPRINTF(x)		printf x
88#else
89#define	DPRINTF(x)
90#endif
91
92static struct dpt_sig dpti_sig = {
93	{ 'd', 'P', 't', 'S', 'i', 'G'},
94	SIG_VERSION,
95#if defined(__i386__)
96	PROC_INTEL,
97#elif defined(__powerpc__)
98	PROC_POWERPC,
99#elif defined(__alpha__)
100	PROC_ALPHA,
101#elif defined(__mips__)
102	PROC_MIPS,
103#elif defined(__sparc64__)
104	PROC_ULTRASPARC,
105#endif
106#if defined(__i386__)
107	PROC_386 | PROC_486 | PROC_PENTIUM | PROC_SEXIUM,
108#else
109	0,
110#endif
111	FT_HBADRVR,
112	0,
113	OEM_DPT,
114	OS_FREE_BSD,	/* XXX */
115	CAP_ABOVE16MB,
116	DEV_ALL,
117	ADF_ALL_SC5,
118	0,
119	0,
120	DPTI_VERSION,
121	DPTI_REVISION,
122	DPTI_SUBREVISION,
123	DPTI_MONTH,
124	DPTI_DAY,
125	DPTI_YEAR,
126	""		/* Will be filled later */
127};
128
129void	dpti_attach(device_t, device_t, void *);
130int	dpti_blinkled(struct dpti_softc *);
131int	dpti_ctlrinfo(struct dpti_softc *, int, void *);
132int	dpti_match(device_t, cfdata_t, void *);
133int	dpti_passthrough(struct dpti_softc *, void *, struct proc *);
134int	dpti_sysinfo(struct dpti_softc *, int, void *);
135
136dev_type_open(dptiopen);
137dev_type_ioctl(dptiioctl);
138
139const struct cdevsw dpti_cdevsw = {
140	dptiopen, nullclose, noread, nowrite, dptiioctl,
141	nostop, notty, nopoll, nommap, nokqfilter, D_OTHER,
142};
143
144extern struct cfdriver dpti_cd;
145
146CFATTACH_DECL(dpti, sizeof(struct dpti_softc),
147    dpti_match, dpti_attach, NULL, NULL);
148
149int
150dpti_match(device_t parent, cfdata_t match, void *aux)
151{
152	struct iop_attach_args *ia;
153	struct iop_softc *iop;
154
155	ia = aux;
156	iop = (struct iop_softc *)parent;
157
158	if (ia->ia_class != I2O_CLASS_ANY || ia->ia_tid != I2O_TID_IOP)
159		return (0);
160
161	if (le16toh(iop->sc_status.orgid) != I2O_ORG_DPT)
162		return (0);
163
164	return (1);
165}
166
167void
168dpti_attach(device_t parent, device_t self, void *aux)
169{
170	struct iop_softc *iop;
171	struct dpti_softc *sc;
172	struct {
173		struct	i2o_param_op_results pr;
174		struct	i2o_param_read_results prr;
175		struct	i2o_dpt_param_exec_iop_buffers dib;
176	} __packed param;
177	int rv;
178
179	sc = device_private(self);
180	iop = device_private(parent);
181
182	/*
183	 * Tell the world what we are.  The description in the signature
184	 * must be no more than 46 bytes long (see dptivar.h).
185	 */
186	printf(": DPT/Adaptec RAID management interface\n");
187	snprintf(dpti_sig.dsDescription, sizeof(dpti_sig.dsDescription),
188	    "NetBSD %s I2O OSM", osrelease);
189
190	rv = iop_field_get_all(iop, I2O_TID_IOP,
191	    I2O_DPT_PARAM_EXEC_IOP_BUFFERS, &param,
192	    sizeof(param), NULL);
193	if (rv != 0)
194		return;
195
196	sc->sc_blinkled = le32toh(param.dib.serialoutputoff) + 8;
197}
198
199int
200dptiopen(dev_t dev, int flag, int mode,
201    struct lwp *l)
202{
203
204	if (device_lookup(&dpti_cd, minor(dev)) == NULL)
205		return (ENXIO);
206
207	return (0);
208}
209
210int
211dptiioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
212{
213	struct iop_softc *iop;
214	struct dpti_softc *sc;
215	struct ioctl_pt *pt;
216	int i, size, rv, linux;
217
218	sc = device_lookup_private(&dpti_cd, minor(dev));
219	iop = (struct iop_softc *)device_parent(&sc->sc_dv);
220	rv = 0;
221
222	if (cmd == PTIOCLINUX) {
223		pt = (struct ioctl_pt *)data;
224		size = IOCPARM_LEN(pt->com);
225		cmd = pt->com & 0xffff;
226		data = pt->data;
227		linux = 1;
228	} else {
229		size = IOCPARM_LEN(cmd);
230		cmd = cmd & 0xffff;
231		linux = 0;
232	}
233
234	switch (cmd) {
235	case DPT_SIGNATURE:
236		if (size > sizeof(dpti_sig))
237			size = sizeof(dpti_sig);
238		memcpy(data, &dpti_sig, size);
239		break;
240
241	case DPT_CTRLINFO:
242		rv = dpti_ctlrinfo(sc, size, data);
243		break;
244
245	case DPT_SYSINFO:
246		rv = dpti_sysinfo(sc, size, data);
247		break;
248
249	case DPT_BLINKLED:
250		if ((i = dpti_blinkled(sc)) == -1)
251			i = 0;
252
253		if (size == 0) {
254			rv = copyout(&i, *(void **)data, sizeof(i));
255			break;
256		}
257
258		*(int *)data = i;
259		break;
260
261	case DPT_TARGET_BUSY:
262		/*
263		 * XXX This is here to stop linux_machdepioctl() from
264		 * whining about an unknown ioctl.
265		 */
266		rv = EIO;
267		break;
268
269	case DPT_I2OUSRCMD:
270		rv = kauth_authorize_device_passthru(l->l_cred, dev,
271		    KAUTH_REQ_DEVICE_RAWIO_PASSTHRU_ALL, data);
272		if (rv)
273			break;
274
275		mutex_enter(&iop->sc_conflock);
276		if (linux) {
277			rv = dpti_passthrough(sc, data, l->l_proc);
278		} else {
279			rv = dpti_passthrough(sc, *(void **)data, l->l_proc);
280		}
281		mutex_exit(&iop->sc_conflock);
282		break;
283
284	case DPT_I2ORESETCMD:
285		printf("%s: I2ORESETCMD not implemented\n",
286		    device_xname(&sc->sc_dv));
287		rv = EOPNOTSUPP;
288		break;
289
290	case DPT_I2ORESCANCMD:
291		mutex_enter(&iop->sc_conflock);
292		rv = iop_reconfigure(iop, 0);
293		mutex_exit(&iop->sc_conflock);
294		break;
295
296	default:
297		rv = ENOTTY;
298		break;
299	}
300
301	return (rv);
302}
303
304int
305dpti_blinkled(struct dpti_softc *sc)
306{
307	struct iop_softc *iop;
308	u_int v;
309
310	iop = (struct iop_softc *)device_parent(&sc->sc_dv);
311
312	v = bus_space_read_1(iop->sc_iot, iop->sc_ioh, sc->sc_blinkled + 0);
313	if (v == 0xbc) {
314		v = bus_space_read_1(iop->sc_iot, iop->sc_ioh,
315		    sc->sc_blinkled + 1);
316		return (v);
317	}
318
319	return (-1);
320}
321
322int
323dpti_ctlrinfo(struct dpti_softc *sc, int size, void *data)
324{
325	struct dpt_ctlrinfo info;
326	struct iop_softc *iop;
327	int rv, i;
328
329	iop = (struct iop_softc *)device_parent(&sc->sc_dv);
330
331	memset(&info, 0, sizeof(info));
332
333	info.length = sizeof(info) - sizeof(u_int16_t);
334	info.drvrHBAnum = device_unit(&sc->sc_dv);
335	info.baseAddr = iop->sc_memaddr;
336	if ((i = dpti_blinkled(sc)) == -1)
337		i = 0;
338	info.blinkState = i;
339	info.pciBusNum = iop->sc_pcibus;
340	info.pciDeviceNum = iop->sc_pcidev;
341	info.hbaFlags = FLG_OSD_PCI_VALID | FLG_OSD_DMA | FLG_OSD_I2O;
342	info.Interrupt = 10;			/* XXX */
343
344	if (size > sizeof(char)) {
345		memcpy(data, &info, min(sizeof(info), size));
346		rv = 0;
347	} else
348		rv = copyout(&info, *(void **)data, sizeof(info));
349
350	return (rv);
351}
352
353int
354dpti_sysinfo(struct dpti_softc *sc, int size, void *data)
355{
356	struct dpt_sysinfo info;
357	int rv;
358#ifdef __i386__
359	int i, j;
360#endif
361
362	memset(&info, 0, sizeof(info));
363
364#ifdef __i386__
365	outb (0x70, 0x12);
366	i = inb(0x71);
367	j = i >> 4;
368	if (i == 0x0f) {
369		outb (0x70, 0x19);
370		j = inb (0x71);
371	}
372	info.drive0CMOS = j;
373
374	j = i & 0x0f;
375	if (i == 0x0f) {
376		outb (0x70, 0x1a);
377		j = inb (0x71);
378	}
379	info.drive1CMOS = j;
380	info.processorFamily = dpti_sig.dsProcessorFamily;
381
382	/*
383	 * Get the conventional memory size from CMOS.
384	 */
385	outb(0x70, 0x16);
386	j = inb(0x71);
387	j <<= 8;
388	outb(0x70, 0x15);
389	j |= inb(0x71);
390	info.conventionalMemSize = j;
391
392	/*
393	 * Get the extended memory size from CMOS.
394	 */
395	outb(0x70, 0x31);
396	j = inb(0x71);
397	j <<= 8;
398	outb(0x70, 0x30);
399	j |= inb(0x71);
400	info.extendedMemSize = j;
401
402	switch (cpu_class) {
403	case CPUCLASS_386:
404		info.processorType = PROC_386;
405		break;
406	case CPUCLASS_486:
407		info.processorType = PROC_486;
408		break;
409	case CPUCLASS_586:
410		info.processorType = PROC_PENTIUM;
411		break;
412	case CPUCLASS_686:
413	default:
414		info.processorType = PROC_SEXIUM;
415		break;
416	}
417
418	info.flags = SI_CMOS_Valid | SI_BusTypeValid |
419	    SI_MemorySizeValid | SI_NO_SmartROM;
420#else
421	info.flags = SI_BusTypeValid | SI_NO_SmartROM;
422#endif
423
424	info.busType = SI_PCI_BUS;
425
426	/*
427	 * Copy out the info structure to the user.
428	 */
429	if (size > sizeof(char)) {
430		memcpy(data, &info, min(sizeof(info), size));
431		rv = 0;
432	} else
433		rv = copyout(&info, *(void **)data, sizeof(info));
434
435	return (rv);
436}
437
438int
439dpti_passthrough(struct dpti_softc *sc, void *data, struct proc *proc)
440{
441	struct iop_softc *iop;
442	struct i2o_msg mh, *mf;
443	struct i2o_reply rh;
444	struct iop_msg *im;
445	struct dpti_ptbuf bufs[IOP_MAX_MSG_XFERS];
446	u_int32_t mbtmp[IOP_MAX_MSG_SIZE / sizeof(u_int32_t)];
447	u_int32_t rbtmp[IOP_MAX_MSG_SIZE / sizeof(u_int32_t)];
448	int rv, msgsize, repsize, sgoff, i, mapped, nbuf, nfrag, j, sz;
449	u_int32_t *p, *pmax;
450
451	iop = (struct iop_softc *)device_parent(&sc->sc_dv);
452	im = NULL;
453
454	if ((rv = dpti_blinkled(sc)) != -1) {
455		if (rv != 0) {
456			aprint_error_dev(&sc->sc_dv, "adapter blinkled = 0x%02x\n", rv);
457			return (EIO);
458		}
459	}
460
461	/*
462	 * Copy in the message frame header and determine the size of the
463	 * full message frame.
464	 */
465	if ((rv = copyin(data, &mh, sizeof(mh))) != 0) {
466		DPRINTF(("%s: message copyin failed\n",
467		    device_xname(&sc->sc_dv)));
468		return (rv);
469	}
470
471	msgsize = (mh.msgflags >> 14) & ~3;
472	if (msgsize < sizeof(mh) || msgsize >= IOP_MAX_MSG_SIZE) {
473		DPRINTF(("%s: bad message frame size\n",
474		    device_xname(&sc->sc_dv)));
475		return (EINVAL);
476	}
477
478	/*
479	 * Handle special commands.
480	 */
481	switch (mh.msgfunc >> 24) {
482	case I2O_EXEC_IOP_RESET:
483		printf("%s: I2O_EXEC_IOP_RESET not implemented\n",
484		    device_xname(&sc->sc_dv));
485		return (EOPNOTSUPP);
486
487	case I2O_EXEC_OUTBOUND_INIT:
488		printf("%s: I2O_EXEC_OUTBOUND_INIT not implemented\n",
489		    device_xname(&sc->sc_dv));
490		return (EOPNOTSUPP);
491
492	case I2O_EXEC_SYS_TAB_SET:
493		printf("%s: I2O_EXEC_SYS_TAB_SET not implemented\n",
494		    device_xname(&sc->sc_dv));
495		return (EOPNOTSUPP);
496
497	case I2O_EXEC_STATUS_GET:
498		if ((rv = iop_status_get(iop, 0)) == 0)
499			rv = copyout(&iop->sc_status, (char *)data + msgsize,
500			    sizeof(iop->sc_status));
501		return (rv);
502	}
503
504	/*
505	 * Copy in the full message frame.
506	 */
507	if ((rv = copyin(data, mbtmp, msgsize)) != 0) {
508		DPRINTF(("%s: full message copyin failed\n",
509		    device_xname(&sc->sc_dv)));
510		return (rv);
511	}
512
513	/*
514	 * Determine the size of the reply frame, and copy it in.
515	 */
516	if ((rv = copyin((char *)data + msgsize, &rh, sizeof(rh))) != 0) {
517		DPRINTF(("%s: reply copyin failed\n",
518		    device_xname(&sc->sc_dv)));
519		return (rv);
520	}
521
522	repsize = (rh.msgflags >> 14) & ~3;
523	if (repsize < sizeof(rh) || repsize >= IOP_MAX_MSG_SIZE) {
524		DPRINTF(("%s: bad reply header size\n",
525		    device_xname(&sc->sc_dv)));
526		return (EINVAL);
527	}
528
529	if ((rv = copyin((char *)data + msgsize, rbtmp, repsize)) != 0) {
530		DPRINTF(("%s: reply too large\n", device_xname(&sc->sc_dv)));
531		return (rv);
532	}
533
534	/*
535	 * If the message has a scatter gather list, it must be comprised of
536	 * simple elements.  If any one transfer contains multiple segments,
537	 * we allocate a temporary buffer for it; otherwise, the buffer will
538	 * be mapped directly.
539	 */
540	mapped = 0;
541	if ((sgoff = ((mh.msgflags >> 4) & 15)) != 0) {
542		if ((sgoff + 2) > (msgsize >> 2)) {
543			DPRINTF(("%s: invalid message size fields\n",
544			    device_xname(&sc->sc_dv)));
545			return (EINVAL);
546		}
547
548		memset(bufs, 0, sizeof(bufs));
549
550		p = mbtmp + sgoff;
551		pmax = mbtmp + (msgsize >> 2) - 2;
552
553		for (nbuf = 0; nbuf < IOP_MAX_MSG_XFERS; nbuf++, p += 2) {
554			if (p > pmax) {
555				DPRINTF(("%s: invalid SGL (1)\n",
556				    device_xname(&sc->sc_dv)));
557				goto bad;
558			}
559
560			if ((p[0] & 0x30000000) != I2O_SGL_SIMPLE) {
561				DPRINTF(("%s: invalid SGL (2)\n",
562				    device_xname(&sc->sc_dv)));
563				goto bad;
564			}
565
566			bufs[nbuf].db_out = (p[0] & I2O_SGL_DATA_OUT) != 0;
567			bufs[nbuf].db_ptr = NULL;
568
569			if ((p[0] & I2O_SGL_END_BUFFER) != 0) {
570				if ((p[0] & 0x00ffffff) > IOP_MAX_XFER) {
571					DPRINTF(("%s: buffer too large\n",
572					    device_xname(&sc->sc_dv)));
573					goto bad;
574				}
575
576				bufs[nbuf].db_ptr = (void *)p[1];
577				bufs[nbuf].db_proc = proc;
578				bufs[nbuf].db_size = p[0] & 0x00ffffff;
579
580				if ((p[0] & I2O_SGL_END) != 0)
581					break;
582
583				continue;
584			}
585
586			/*
587			 * The buffer has multiple segments.  Determine the
588			 * total size.
589			 */
590			nfrag = 0;
591			sz = 0;
592			for (; p <= pmax; p += 2) {
593				if (nfrag == DPTI_MAX_SEGS) {
594					DPRINTF(("%s: too many segments\n",
595					    device_xname(&sc->sc_dv)));
596					goto bad;
597				}
598
599				bufs[nbuf].db_frags[nfrag].iov_len =
600				    p[0] & 0x00ffffff;
601				bufs[nbuf].db_frags[nfrag].iov_base =
602				    (void *)p[1];
603
604				sz += p[0] & 0x00ffffff;
605				nfrag++;
606
607				if ((p[0] & I2O_SGL_END) != 0) {
608					if ((p[0] & I2O_SGL_END_BUFFER) == 0) {
609						DPRINTF((
610						    "%s: invalid SGL (3)\n",
611						    device_xname(&sc->sc_dv)));
612						goto bad;
613					}
614					break;
615				}
616				if ((p[0] & I2O_SGL_END_BUFFER) != 0)
617					break;
618			}
619			bufs[nbuf].db_nfrag = nfrag;
620
621			if (p > pmax) {
622				DPRINTF(("%s: invalid SGL (4)\n",
623				    device_xname(&sc->sc_dv)));
624				goto bad;
625			}
626
627			if (sz > IOP_MAX_XFER) {
628				DPRINTF(("%s: buffer too large\n",
629				    device_xname(&sc->sc_dv)));
630				goto bad;
631			}
632
633			bufs[nbuf].db_size = sz;
634			bufs[nbuf].db_ptr = malloc(sz, M_DEVBUF, M_WAITOK);
635			if (bufs[nbuf].db_ptr == NULL) {
636				DPRINTF(("%s: allocation failure\n",
637				    device_xname(&sc->sc_dv)));
638				rv = ENOMEM;
639				goto bad;
640			}
641
642			for (i = 0, sz = 0; i < bufs[nbuf].db_nfrag; i++) {
643				rv = copyin(bufs[nbuf].db_frags[i].iov_base,
644				    (char *)bufs[nbuf].db_ptr + sz,
645				    bufs[nbuf].db_frags[i].iov_len);
646				if (rv != 0) {
647					DPRINTF(("%s: frag copyin\n",
648					    device_xname(&sc->sc_dv)));
649					goto bad;
650				}
651				sz += bufs[nbuf].db_frags[i].iov_len;
652			}
653
654			if ((p[0] & I2O_SGL_END) != 0)
655				break;
656		}
657
658		if (nbuf == IOP_MAX_MSG_XFERS) {
659			DPRINTF(("%s: too many transfers\n",
660			    device_xname(&sc->sc_dv)));
661			goto bad;
662		}
663	} else
664		nbuf = -1;
665
666	/*
667	 * Allocate a wrapper, and adjust the message header fields to
668	 * indicate that no scatter-gather list is currently present.
669	 */
670
671	im = iop_msg_alloc(iop, IM_WAIT | IM_NOSTATUS);
672	im->im_rb = (struct i2o_reply *)rbtmp;
673	mf = (struct i2o_msg *)mbtmp;
674	mf->msgictx = IOP_ICTX;
675	mf->msgtctx = im->im_tctx;
676
677	if (sgoff != 0)
678		mf->msgflags = (mf->msgflags & 0xff0f) | (sgoff << 16);
679
680	/*
681	 * Map the data transfer(s).
682	 */
683	for (i = 0; i <= nbuf; i++) {
684		rv = iop_msg_map(iop, im, mbtmp, bufs[i].db_ptr,
685		    bufs[i].db_size, bufs[i].db_out, bufs[i].db_proc);
686		if (rv != 0) {
687			DPRINTF(("%s: msg_map failed, rv = %d\n",
688			    device_xname(&sc->sc_dv), rv));
689			goto bad;
690		}
691		mapped = 1;
692	}
693
694	/*
695	 * Start the command and sleep until it completes.
696	 */
697	if ((rv = iop_msg_post(iop, im, mbtmp, 5*60*1000)) != 0)
698		goto bad;
699
700	/*
701	 * Copy out the reply frame.
702	 */
703	if ((rv = copyout(rbtmp, (char *)data + msgsize, repsize)) != 0) {
704		DPRINTF(("%s: reply copyout() failed\n",
705		    device_xname(&sc->sc_dv)));
706	}
707
708 bad:
709	/*
710	 * Free resources and return to the caller.
711	 */
712	if (im != NULL) {
713		if (mapped)
714			iop_msg_unmap(iop, im);
715		iop_msg_free(iop, im);
716	}
717
718	for (i = 0; i <= nbuf; i++) {
719		if (bufs[i].db_proc != NULL)
720			continue;
721
722		if (!bufs[i].db_out && rv == 0) {
723			for (j = 0, sz = 0; j < bufs[i].db_nfrag; j++) {
724				rv = copyout((char *)bufs[i].db_ptr + sz,
725				    bufs[i].db_frags[j].iov_base,
726				    bufs[i].db_frags[j].iov_len);
727				if (rv != 0)
728					break;
729				sz += bufs[i].db_frags[j].iov_len;
730			}
731		}
732
733		if (bufs[i].db_ptr != NULL)
734			free(bufs[i].db_ptr, M_DEVBUF);
735	}
736
737	return (rv);
738}
739