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