The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/i2o/dpti.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*      $NetBSD: dpti.c,v 1.30.2.1 2006/12/04 18:34:16 tron 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.2.1 2006/12/04 18:34:16 tron 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, &param,
  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,
  281                     KAUTH_REQ_DEVICE_RAWIO_PASSTHRU_ALL, data);
  282                 if (rv)
  283                         break;
  284 
  285                 if (sc->sc_nactive++ >= 2)
  286                         tsleep(&sc->sc_nactive, PRIBIO, "dptislp", 0);
  287 
  288                 if (linux)
  289                         rv = dpti_passthrough(sc, data, l->l_proc);
  290                 else
  291                         rv = dpti_passthrough(sc, *(caddr_t *)data, l->l_proc);
  292 
  293                 sc->sc_nactive--;
  294                 wakeup_one(&sc->sc_nactive);
  295                 break;
  296 
  297         case DPT_I2ORESETCMD:
  298                 printf("%s: I2ORESETCMD not implemented\n",
  299                     sc->sc_dv.dv_xname);
  300                 rv = EOPNOTSUPP;
  301                 break;
  302 
  303         case DPT_I2ORESCANCMD:
  304                 if ((rv = lockmgr(&iop->sc_conflock, LK_EXCLUSIVE, NULL)) != 0)
  305                         break;
  306                 rv = iop_reconfigure(iop, 0);
  307                 lockmgr(&iop->sc_conflock, LK_RELEASE, NULL);
  308                 break;
  309 
  310         default:
  311                 rv = ENOTTY;
  312                 break;
  313         }
  314 
  315         return (rv);
  316 }
  317 
  318 int
  319 dpti_blinkled(struct dpti_softc *sc)
  320 {
  321         struct iop_softc *iop;
  322         u_int v;
  323 
  324         iop = (struct iop_softc *)device_parent(&sc->sc_dv);
  325 
  326         v = bus_space_read_1(iop->sc_iot, iop->sc_ioh, sc->sc_blinkled + 0);
  327         if (v == 0xbc) {
  328                 v = bus_space_read_1(iop->sc_iot, iop->sc_ioh,
  329                     sc->sc_blinkled + 1);
  330                 return (v);
  331         }
  332 
  333         return (-1);
  334 }
  335 
  336 int
  337 dpti_ctlrinfo(struct dpti_softc *sc, int size, caddr_t data)
  338 {
  339         struct dpt_ctlrinfo info;
  340         struct iop_softc *iop;
  341         int rv, i;
  342 
  343         iop = (struct iop_softc *)device_parent(&sc->sc_dv);
  344 
  345         memset(&info, 0, sizeof(info));
  346 
  347         info.length = sizeof(info) - sizeof(u_int16_t);
  348         info.drvrHBAnum = device_unit(&sc->sc_dv);
  349         info.baseAddr = iop->sc_memaddr;
  350         if ((i = dpti_blinkled(sc)) == -1)
  351                 i = 0;
  352         info.blinkState = i;
  353         info.pciBusNum = iop->sc_pcibus;
  354         info.pciDeviceNum = iop->sc_pcidev;
  355         info.hbaFlags = FLG_OSD_PCI_VALID | FLG_OSD_DMA | FLG_OSD_I2O;
  356         info.Interrupt = 10;                    /* XXX */
  357 
  358         if (size > sizeof(*data)) {
  359                 memcpy(data, &info, min(sizeof(info), size));
  360                 rv = 0;
  361         } else
  362                 rv = copyout(&info, *(caddr_t *)data, sizeof(info));
  363 
  364         return (rv);
  365 }
  366 
  367 int
  368 dpti_sysinfo(struct dpti_softc *sc, int size, caddr_t data)
  369 {
  370         struct dpt_sysinfo info;
  371         int rv;
  372 #ifdef __i386__
  373         int i, j;
  374 #endif
  375 
  376         memset(&info, 0, sizeof(info));
  377 
  378 #ifdef __i386__
  379         outb (0x70, 0x12);
  380         i = inb(0x71);
  381         j = i >> 4;
  382         if (i == 0x0f) {
  383                 outb (0x70, 0x19);
  384                 j = inb (0x71);
  385         }
  386         info.drive0CMOS = j;
  387 
  388         j = i & 0x0f;
  389         if (i == 0x0f) {
  390                 outb (0x70, 0x1a);
  391                 j = inb (0x71);
  392         }
  393         info.drive1CMOS = j;
  394         info.processorFamily = dpti_sig.dsProcessorFamily;
  395 
  396         /*
  397          * Get the conventional memory size from CMOS.
  398          */
  399         outb(0x70, 0x16);
  400         j = inb(0x71);
  401         j <<= 8;
  402         outb(0x70, 0x15);
  403         j |= inb(0x71);
  404         info.conventionalMemSize = j;
  405 
  406         /*
  407          * Get the extended memory size from CMOS.
  408          */
  409         outb(0x70, 0x31);
  410         j = inb(0x71);
  411         j <<= 8;
  412         outb(0x70, 0x30);
  413         j |= inb(0x71);
  414         info.extendedMemSize = j;
  415 
  416         switch (cpu_class) {
  417         case CPUCLASS_386:
  418                 info.processorType = PROC_386;
  419                 break;
  420         case CPUCLASS_486:
  421                 info.processorType = PROC_486;
  422                 break;
  423         case CPUCLASS_586:
  424                 info.processorType = PROC_PENTIUM;
  425                 break;
  426         case CPUCLASS_686:
  427         default:
  428                 info.processorType = PROC_SEXIUM;
  429                 break;
  430         }
  431 
  432         info.flags = SI_CMOS_Valid | SI_BusTypeValid |
  433             SI_MemorySizeValid | SI_NO_SmartROM;
  434 #else
  435         info.flags = SI_BusTypeValid | SI_NO_SmartROM;
  436 #endif
  437 
  438         info.busType = SI_PCI_BUS;
  439 
  440         /*
  441          * Copy out the info structure to the user.
  442          */
  443         if (size > sizeof(*data)) {
  444                 memcpy(data, &info, min(sizeof(info), size));
  445                 rv = 0;
  446         } else
  447                 rv = copyout(&info, *(caddr_t *)data, sizeof(info));
  448 
  449         return (rv);
  450 }
  451 
  452 int
  453 dpti_passthrough(struct dpti_softc *sc, caddr_t data, struct proc *proc)
  454 {
  455         struct iop_softc *iop;
  456         struct i2o_msg mh, *mf;
  457         struct i2o_reply rh;
  458         struct iop_msg *im;
  459         struct dpti_ptbuf bufs[IOP_MAX_MSG_XFERS];
  460         u_int32_t mbtmp[IOP_MAX_MSG_SIZE / sizeof(u_int32_t)];
  461         u_int32_t rbtmp[IOP_MAX_MSG_SIZE / sizeof(u_int32_t)];
  462         int rv, msgsize, repsize, sgoff, i, mapped, nbuf, nfrag, j, sz;
  463         u_int32_t *p, *pmax;
  464 
  465         iop = (struct iop_softc *)device_parent(&sc->sc_dv);
  466         im = NULL;
  467 
  468         if ((rv = dpti_blinkled(sc)) != -1) {
  469                 if (rv != 0) {
  470                         printf("%s: adapter blinkled = 0x%02x\n",
  471                             sc->sc_dv.dv_xname, rv);
  472                         return (EIO);
  473                 }
  474         }
  475 
  476         /*
  477          * Copy in the message frame header and determine the size of the
  478          * full message frame.
  479          */
  480         if ((rv = copyin(data, &mh, sizeof(mh))) != 0) {
  481                 DPRINTF(("%s: message copyin failed\n",
  482                     sc->sc_dv.dv_xname));
  483                 return (rv);
  484         }
  485 
  486         msgsize = (mh.msgflags >> 14) & ~3;
  487         if (msgsize < sizeof(mh) || msgsize >= IOP_MAX_MSG_SIZE) {
  488                 DPRINTF(("%s: bad message frame size\n",
  489                     sc->sc_dv.dv_xname));
  490                 return (EINVAL);
  491         }
  492 
  493         /*
  494          * Handle special commands.
  495          */
  496         switch (mh.msgfunc >> 24) {
  497         case I2O_EXEC_IOP_RESET:
  498                 printf("%s: I2O_EXEC_IOP_RESET not implemented\n",
  499                     sc->sc_dv.dv_xname);
  500                 return (EOPNOTSUPP);
  501 
  502         case I2O_EXEC_OUTBOUND_INIT:
  503                 printf("%s: I2O_EXEC_OUTBOUND_INIT not implemented\n",
  504                     sc->sc_dv.dv_xname);
  505                 return (EOPNOTSUPP);
  506 
  507         case I2O_EXEC_SYS_TAB_SET:
  508                 printf("%s: I2O_EXEC_SYS_TAB_SET not implemented\n",
  509                     sc->sc_dv.dv_xname);
  510                 return (EOPNOTSUPP);
  511 
  512         case I2O_EXEC_STATUS_GET:
  513                 if ((rv = iop_status_get(iop, 0)) == 0)
  514                         rv = copyout(&iop->sc_status, data + msgsize,
  515                             sizeof(iop->sc_status));
  516                 return (rv);
  517         }
  518 
  519         /*
  520          * Copy in the full message frame.
  521          */
  522         if ((rv = copyin(data, mbtmp, msgsize)) != 0) {
  523                 DPRINTF(("%s: full message copyin failed\n",
  524                     sc->sc_dv.dv_xname));
  525                 return (rv);
  526         }
  527 
  528         /*
  529          * Determine the size of the reply frame, and copy it in.
  530          */
  531         if ((rv = copyin(data + msgsize, &rh, sizeof(rh))) != 0) {
  532                 DPRINTF(("%s: reply copyin failed\n",
  533                     sc->sc_dv.dv_xname));
  534                 return (rv);
  535         }
  536 
  537         repsize = (rh.msgflags >> 14) & ~3;
  538         if (repsize < sizeof(rh) || repsize >= IOP_MAX_MSG_SIZE) {
  539                 DPRINTF(("%s: bad reply header size\n",
  540                     sc->sc_dv.dv_xname));
  541                 return (EINVAL);
  542         }
  543 
  544         if ((rv = copyin(data + msgsize, rbtmp, repsize)) != 0) {
  545                 DPRINTF(("%s: reply too large\n", sc->sc_dv.dv_xname));
  546                 return (rv);
  547         }
  548 
  549         /*
  550          * If the message has a scatter gather list, it must be comprised of
  551          * simple elements.  If any one transfer contains multiple segments,
  552          * we allocate a temporary buffer for it; otherwise, the buffer will
  553          * be mapped directly.
  554          */
  555         mapped = 0;
  556         if ((sgoff = ((mh.msgflags >> 4) & 15)) != 0) {
  557                 if ((sgoff + 2) > (msgsize >> 2)) {
  558                         DPRINTF(("%s: invalid message size fields\n",
  559                             sc->sc_dv.dv_xname));
  560                         return (EINVAL);
  561                 }
  562 
  563                 memset(bufs, 0, sizeof(bufs));
  564 
  565                 p = mbtmp + sgoff;
  566                 pmax = mbtmp + (msgsize >> 2) - 2;
  567 
  568                 for (nbuf = 0; nbuf < IOP_MAX_MSG_XFERS; nbuf++, p += 2) {
  569                         if (p > pmax) {
  570                                 DPRINTF(("%s: invalid SGL (1)\n",
  571                                     sc->sc_dv.dv_xname));
  572                                 goto bad;
  573                         }
  574 
  575                         if ((p[0] & 0x30000000) != I2O_SGL_SIMPLE) {
  576                                 DPRINTF(("%s: invalid SGL (2)\n",
  577                                     sc->sc_dv.dv_xname));
  578                                 goto bad;
  579                         }
  580 
  581                         bufs[nbuf].db_out = (p[0] & I2O_SGL_DATA_OUT) != 0;
  582                         bufs[nbuf].db_ptr = NULL;
  583 
  584                         if ((p[0] & I2O_SGL_END_BUFFER) != 0) {
  585                                 if ((p[0] & 0x00ffffff) > IOP_MAX_XFER) {
  586                                         DPRINTF(("%s: buffer too large\n",
  587                                             sc->sc_dv.dv_xname));
  588                                         goto bad;
  589                                 }
  590 
  591                                 bufs[nbuf].db_ptr = (caddr_t)p[1];
  592                                 bufs[nbuf].db_proc = proc;
  593                                 bufs[nbuf].db_size = p[0] & 0x00ffffff;
  594 
  595                                 if ((p[0] & I2O_SGL_END) != 0)
  596                                         break;
  597 
  598                                 continue;
  599                         }
  600 
  601                         /*
  602                          * The buffer has multiple segments.  Determine the
  603                          * total size.
  604                          */
  605                         nfrag = 0;
  606                         sz = 0;
  607                         for (; p <= pmax; p += 2) {
  608                                 if (nfrag == DPTI_MAX_SEGS) {
  609                                         DPRINTF(("%s: too many segments\n",
  610                                             sc->sc_dv.dv_xname));
  611                                         goto bad;
  612                                 }
  613 
  614                                 bufs[nbuf].db_frags[nfrag].iov_len =
  615                                     p[0] & 0x00ffffff;
  616                                 bufs[nbuf].db_frags[nfrag].iov_base =
  617                                     (void *)p[1];
  618 
  619                                 sz += p[0] & 0x00ffffff;
  620                                 nfrag++;
  621 
  622                                 if ((p[0] & I2O_SGL_END) != 0) {
  623                                         if ((p[0] & I2O_SGL_END_BUFFER) == 0) {
  624                                                 DPRINTF((
  625                                                     "%s: invalid SGL (3)\n",
  626                                                     sc->sc_dv.dv_xname));
  627                                                 goto bad;
  628                                         }
  629                                         break;
  630                                 }
  631                                 if ((p[0] & I2O_SGL_END_BUFFER) != 0)
  632                                         break;
  633                         }
  634                         bufs[nbuf].db_nfrag = nfrag;
  635 
  636                         if (p > pmax) {
  637                                 DPRINTF(("%s: invalid SGL (4)\n",
  638                                     sc->sc_dv.dv_xname));
  639                                 goto bad;
  640                         }
  641 
  642                         if (sz > IOP_MAX_XFER) {
  643                                 DPRINTF(("%s: buffer too large\n",
  644                                     sc->sc_dv.dv_xname));
  645                                 goto bad;
  646                         }
  647 
  648                         bufs[nbuf].db_size = sz;
  649                         bufs[nbuf].db_ptr = malloc(sz, M_DEVBUF, M_WAITOK);
  650                         if (bufs[nbuf].db_ptr == NULL) {
  651                                 DPRINTF(("%s: allocation failure\n",
  652                                     sc->sc_dv.dv_xname));
  653                                 rv = ENOMEM;
  654                                 goto bad;
  655                         }
  656 
  657                         for (i = 0, sz = 0; i < bufs[nbuf].db_nfrag; i++) {
  658                                 rv = copyin(bufs[nbuf].db_frags[i].iov_base,
  659                                     bufs[nbuf].db_ptr + sz,
  660                                     bufs[nbuf].db_frags[i].iov_len);
  661                                 if (rv != 0) {
  662                                         DPRINTF(("%s: frag copyin\n",
  663                                             sc->sc_dv.dv_xname));
  664                                         goto bad;
  665                                 }
  666                                 sz += bufs[nbuf].db_frags[i].iov_len;
  667                         }
  668 
  669                         if ((p[0] & I2O_SGL_END) != 0)
  670                                 break;
  671                 }
  672 
  673                 if (nbuf == IOP_MAX_MSG_XFERS) {
  674                         DPRINTF(("%s: too many transfers\n",
  675                             sc->sc_dv.dv_xname));
  676                         goto bad;
  677                 }
  678         } else
  679                 nbuf = -1;
  680 
  681         /*
  682          * Allocate a wrapper, and adjust the message header fields to
  683          * indicate that no scatter-gather list is currently present.
  684          */
  685 
  686         im = iop_msg_alloc(iop, IM_WAIT | IM_NOSTATUS);
  687         im->im_rb = (struct i2o_reply *)rbtmp;
  688         mf = (struct i2o_msg *)mbtmp;
  689         mf->msgictx = IOP_ICTX;
  690         mf->msgtctx = im->im_tctx;
  691 
  692         if (sgoff != 0)
  693                 mf->msgflags = (mf->msgflags & 0xff0f) | (sgoff << 16);
  694 
  695         /*
  696          * Map the data transfer(s).
  697          */
  698         for (i = 0; i <= nbuf; i++) {
  699                 rv = iop_msg_map(iop, im, mbtmp, bufs[i].db_ptr,
  700                     bufs[i].db_size, bufs[i].db_out, bufs[i].db_proc);
  701                 if (rv != 0) {
  702                         DPRINTF(("%s: msg_map failed, rv = %d\n",
  703                             sc->sc_dv.dv_xname, rv));
  704                         goto bad;
  705                 }
  706                 mapped = 1;
  707         }
  708 
  709         /*
  710          * Start the command and sleep until it completes.
  711          */
  712         if ((rv = iop_msg_post(iop, im, mbtmp, 5*60*1000)) != 0)
  713                 goto bad;
  714 
  715         /*
  716          * Copy out the reply frame.
  717          */
  718         if ((rv = copyout(rbtmp, data + msgsize, repsize)) != 0) {
  719                 DPRINTF(("%s: reply copyout() failed\n",
  720                     sc->sc_dv.dv_xname));
  721         }
  722 
  723  bad:
  724         /*
  725          * Free resources and return to the caller.
  726          */
  727         if (im != NULL) {
  728                 if (mapped)
  729                         iop_msg_unmap(iop, im);
  730                 iop_msg_free(iop, im);
  731         }
  732 
  733         for (i = 0; i <= nbuf; i++) {
  734                 if (bufs[i].db_proc != NULL)
  735                         continue;
  736 
  737                 if (!bufs[i].db_out && rv == 0) {
  738                         for (j = 0, sz = 0; j < bufs[i].db_nfrag; j++) {
  739                                 rv = copyout(bufs[i].db_ptr + sz,
  740                                     bufs[i].db_frags[j].iov_base,
  741                                     bufs[i].db_frags[j].iov_len);
  742                                 if (rv != 0)
  743                                         break;
  744                                 sz += bufs[i].db_frags[j].iov_len;
  745                         }
  746                 }
  747 
  748                 if (bufs[i].db_ptr != NULL)
  749                         free(bufs[i].db_ptr, M_DEVBUF);
  750         }
  751 
  752         return (rv);
  753 }

Cache object: c0a45bcd22be3ee17c2706a4d06665e4


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.