dpti.c revision 1.28 1 /* $NetBSD: dpti.c,v 1.28 2006/10/12 01:30:58 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.28 2006/10/12 01:30:58 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
82 #include <uvm/uvm_extern.h>
83
84 #include <machine/bus.h>
85 #ifdef __i386__
86 #include <machine/pio.h>
87 #endif
88
89 #include <dev/i2o/i2o.h>
90 #include <dev/i2o/i2odpt.h>
91 #include <dev/i2o/iopio.h>
92 #include <dev/i2o/iopvar.h>
93 #include <dev/i2o/dptivar.h>
94
95 #ifdef I2ODEBUG
96 #define DPRINTF(x) printf x
97 #else
98 #define DPRINTF(x)
99 #endif
100
101 static struct dpt_sig dpti_sig = {
102 { 'd', 'P', 't', 'S', 'i', 'G'},
103 SIG_VERSION,
104 #if defined(__i386__)
105 PROC_INTEL,
106 #elif defined(__powerpc__)
107 PROC_POWERPC,
108 #elif defined(__alpha__)
109 PROC_ALPHA,
110 #elif defined(__mips__)
111 PROC_MIPS,
112 #elif defined(__sparc64__)
113 PROC_ULTRASPARC,
114 #endif
115 #if defined(__i386__)
116 PROC_386 | PROC_486 | PROC_PENTIUM | PROC_SEXIUM,
117 #else
118 0,
119 #endif
120 FT_HBADRVR,
121 0,
122 OEM_DPT,
123 OS_FREE_BSD, /* XXX */
124 CAP_ABOVE16MB,
125 DEV_ALL,
126 ADF_ALL_SC5,
127 0,
128 0,
129 DPTI_VERSION,
130 DPTI_REVISION,
131 DPTI_SUBREVISION,
132 DPTI_MONTH,
133 DPTI_DAY,
134 DPTI_YEAR,
135 "" /* Will be filled later */
136 };
137
138 void dpti_attach(struct device *, struct device *, void *);
139 int dpti_blinkled(struct dpti_softc *);
140 int dpti_ctlrinfo(struct dpti_softc *, int, caddr_t);
141 int dpti_match(struct device *, struct cfdata *, void *);
142 int dpti_passthrough(struct dpti_softc *, caddr_t, struct proc *);
143 int dpti_sysinfo(struct dpti_softc *, int, caddr_t);
144
145 dev_type_open(dptiopen);
146 dev_type_ioctl(dptiioctl);
147
148 const struct cdevsw dpti_cdevsw = {
149 dptiopen, nullclose, noread, nowrite, dptiioctl,
150 nostop, notty, nopoll, nommap, nokqfilter, D_OTHER,
151 };
152
153 extern struct cfdriver dpti_cd;
154
155 CFATTACH_DECL(dpti, sizeof(struct dpti_softc),
156 dpti_match, dpti_attach, NULL, NULL);
157
158 int
159 dpti_match(struct device *parent, struct cfdata *match __unused, void *aux)
160 {
161 struct iop_attach_args *ia;
162 struct iop_softc *iop;
163
164 ia = aux;
165 iop = (struct iop_softc *)parent;
166
167 if (ia->ia_class != I2O_CLASS_ANY || ia->ia_tid != I2O_TID_IOP)
168 return (0);
169
170 if (le16toh(iop->sc_status.orgid) != I2O_ORG_DPT)
171 return (0);
172
173 return (1);
174 }
175
176 void
177 dpti_attach(struct device *parent, struct device *self, void *aux __unused)
178 {
179 struct iop_softc *iop;
180 struct dpti_softc *sc;
181 struct {
182 struct i2o_param_op_results pr;
183 struct i2o_param_read_results prr;
184 struct i2o_dpt_param_exec_iop_buffers dib;
185 } __attribute__ ((__packed__)) param;
186 int rv;
187
188 sc = device_private(self);
189 iop = device_private(parent);
190
191 /*
192 * Tell the world what we are. The description in the signature
193 * must be no more than 46 bytes long (see dptivar.h).
194 */
195 printf(": DPT/Adaptec RAID management interface\n");
196 snprintf(dpti_sig.dsDescription, sizeof(dpti_sig.dsDescription),
197 "NetBSD %s I2O OSM", osrelease);
198
199 rv = iop_field_get_all(iop, I2O_TID_IOP,
200 I2O_DPT_PARAM_EXEC_IOP_BUFFERS, ¶m,
201 sizeof(param), NULL);
202 if (rv != 0)
203 return;
204
205 sc->sc_blinkled = le32toh(param.dib.serialoutputoff) + 8;
206 }
207
208 int
209 dptiopen(dev_t dev, int flag __unused, int mode __unused,
210 struct lwp *l __unused)
211 {
212
213 if (device_lookup(&dpti_cd, minor(dev)) == NULL)
214 return (ENXIO);
215
216 return (0);
217 }
218
219 int
220 dptiioctl(dev_t dev, u_long cmd, caddr_t data, int flag __unused, struct lwp *l)
221 {
222 struct iop_softc *iop;
223 struct dpti_softc *sc;
224 struct ioctl_pt *pt;
225 int i, size, rv, linux;
226
227 sc = device_lookup(&dpti_cd, minor(dev));
228 iop = (struct iop_softc *)device_parent(&sc->sc_dv);
229 rv = 0;
230
231 if (cmd == PTIOCLINUX) {
232 pt = (struct ioctl_pt *)data;
233 size = IOCPARM_LEN(pt->com);
234 cmd = pt->com & 0xffff;
235 data = pt->data;
236 linux = 1;
237 } else {
238 size = IOCPARM_LEN(cmd);
239 cmd = cmd & 0xffff;
240 linux = 0;
241 }
242
243 switch (cmd) {
244 case DPT_SIGNATURE:
245 if (size > sizeof(dpti_sig))
246 size = sizeof(dpti_sig);
247 memcpy(data, &dpti_sig, size);
248 break;
249
250 case DPT_CTRLINFO:
251 rv = dpti_ctlrinfo(sc, size, data);
252 break;
253
254 case DPT_SYSINFO:
255 rv = dpti_sysinfo(sc, size, data);
256 break;
257
258 case DPT_BLINKLED:
259 if ((i = dpti_blinkled(sc)) == -1)
260 i = 0;
261
262 if (size == 0) {
263 rv = copyout(&i, *(caddr_t *)data, sizeof(i));
264 break;
265 }
266
267 *(int *)data = i;
268 break;
269
270 case DPT_TARGET_BUSY:
271 /*
272 * XXX This is here to stop linux_machdepioctl() from
273 * whining about an unknown ioctl.
274 */
275 rv = EIO;
276 break;
277
278 case DPT_I2OUSRCMD:
279 if (securelevel > 1) {
280 rv = EPERM;
281 break;
282 }
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 __unused, 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