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/sbus/isp_sbus.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: isp_sbus.c,v 1.62 2004/03/17 17:04:58 pk Exp $ */
    2 /*
    3  * This driver, which is contained in NetBSD in the files:
    4  *
    5  *      sys/dev/ic/isp.c
    6  *      sys/dev/ic/isp_inline.h
    7  *      sys/dev/ic/isp_netbsd.c
    8  *      sys/dev/ic/isp_netbsd.h
    9  *      sys/dev/ic/isp_target.c
   10  *      sys/dev/ic/isp_target.h
   11  *      sys/dev/ic/isp_tpublic.h
   12  *      sys/dev/ic/ispmbox.h
   13  *      sys/dev/ic/ispreg.h
   14  *      sys/dev/ic/ispvar.h
   15  *      sys/microcode/isp/asm_sbus.h
   16  *      sys/microcode/isp/asm_1040.h
   17  *      sys/microcode/isp/asm_1080.h
   18  *      sys/microcode/isp/asm_12160.h
   19  *      sys/microcode/isp/asm_2100.h
   20  *      sys/microcode/isp/asm_2200.h
   21  *      sys/pci/isp_pci.c
   22  *      sys/sbus/isp_sbus.c
   23  *
   24  * Is being actively maintained by Matthew Jacob (mjacob@NetBSD.org).
   25  * This driver also is shared source with FreeBSD, OpenBSD, Linux, Solaris,
   26  * Linux versions. This tends to be an interesting maintenance problem.
   27  *
   28  * Please coordinate with Matthew Jacob on changes you wish to make here.
   29  */
   30 /*
   31  * SBus specific probe and attach routines for Qlogic ISP SCSI adapters.
   32  *
   33  * Copyright (c) 1997, 2001 by Matthew Jacob
   34  * NASA AMES Research Center
   35  * All rights reserved.
   36  *
   37  * Redistribution and use in source and binary forms, with or without
   38  * modification, are permitted provided that the following conditions
   39  * are met:
   40  * 1. Redistributions of source code must retain the above copyright
   41  *    notice immediately at the beginning of the file, without modification,
   42  *    this list of conditions, and the following disclaimer.
   43  * 2. Redistributions in binary form must reproduce the above copyright
   44  *    notice, this list of conditions and the following disclaimer in the
   45  *    documentation and/or other materials provided with the distribution.
   46  *
   47  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   48  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   49  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   50  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
   51  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   52  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   53  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   54  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   55  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   56  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   57  * SUCH DAMAGE.
   58  *
   59  */
   60 
   61 #include <sys/cdefs.h>
   62 __KERNEL_RCSID(0, "$NetBSD: isp_sbus.c,v 1.62 2004/03/17 17:04:58 pk Exp $");
   63 
   64 #include <sys/param.h>
   65 #include <sys/systm.h>
   66 #include <sys/device.h>
   67 #include <sys/kernel.h>
   68 #include <sys/malloc.h>
   69 #include <sys/queue.h>
   70 #include <dev/ic/isp_netbsd.h>
   71 #include <machine/intr.h>
   72 #include <machine/autoconf.h>
   73 #include <dev/microcode/isp/asm_sbus.h>
   74 #include <dev/sbus/sbusvar.h>
   75 #include <sys/reboot.h>
   76 
   77 static void isp_sbus_reset1(struct ispsoftc *);
   78 static int isp_sbus_intr(void *);
   79 static int
   80 isp_sbus_rd_isr(struct ispsoftc *, u_int16_t *, u_int16_t *, u_int16_t *);
   81 static u_int16_t isp_sbus_rd_reg(struct ispsoftc *, int);
   82 static void isp_sbus_wr_reg (struct ispsoftc *, int, u_int16_t);
   83 static int isp_sbus_mbxdma(struct ispsoftc *);
   84 static int isp_sbus_dmasetup(struct ispsoftc *, XS_T *, ispreq_t *, u_int16_t *,
   85     u_int16_t);
   86 static void isp_sbus_dmateardown(struct ispsoftc *, XS_T *, u_int16_t);
   87 
   88 #ifndef ISP_1000_RISC_CODE
   89 #define ISP_1000_RISC_CODE      NULL
   90 #endif
   91 
   92 static struct ispmdvec mdvec = {
   93         isp_sbus_rd_isr,
   94         isp_sbus_rd_reg,
   95         isp_sbus_wr_reg,
   96         isp_sbus_mbxdma,
   97         isp_sbus_dmasetup,
   98         isp_sbus_dmateardown,
   99         NULL,
  100         isp_sbus_reset1,
  101         NULL,
  102         ISP_1000_RISC_CODE
  103 };
  104 
  105 struct isp_sbussoftc {
  106         struct ispsoftc sbus_isp;
  107         struct sbusdev  sbus_sd;
  108         sdparam         sbus_dev;
  109         bus_space_tag_t sbus_bustag;
  110         bus_space_handle_t sbus_reg;
  111         int             sbus_node;
  112         int             sbus_pri;
  113         struct ispmdvec sbus_mdvec;
  114         bus_dmamap_t    *sbus_dmamap;
  115         int16_t         sbus_poff[_NREG_BLKS];
  116 };
  117 
  118 
  119 static int isp_match(struct device *, struct cfdata *, void *);
  120 static void isp_sbus_attach(struct device *, struct device *, void *);
  121 CFATTACH_DECL(isp_sbus, sizeof (struct isp_sbussoftc),
  122     isp_match, isp_sbus_attach, NULL, NULL);
  123 
  124 static int
  125 isp_match(struct device *parent, struct cfdata *cf, void *aux)
  126 {
  127         int rv;
  128 #ifdef DEBUG
  129         static int oneshot = 1;
  130 #endif
  131         struct sbus_attach_args *sa = aux;
  132 
  133         rv = (strcmp(cf->cf_name, sa->sa_name) == 0 ||
  134                 strcmp("PTI,ptisp", sa->sa_name) == 0 ||
  135                 strcmp("ptisp", sa->sa_name) == 0 ||
  136                 strcmp("SUNW,isp", sa->sa_name) == 0 ||
  137                 strcmp("QLGC,isp", sa->sa_name) == 0);
  138 #ifdef DEBUG
  139         if (rv && oneshot) {
  140                 oneshot = 0;
  141                 printf("Qlogic ISP Driver, NetBSD (sbus) Platform Version "
  142                     "%d.%d Core Version %d.%d\n",
  143                     ISP_PLATFORM_VERSION_MAJOR, ISP_PLATFORM_VERSION_MINOR,
  144                     ISP_CORE_VERSION_MAJOR, ISP_CORE_VERSION_MINOR);
  145         }
  146 #endif
  147         return (rv);
  148 }
  149 
  150 
  151 static void
  152 isp_sbus_attach(struct device *parent, struct device *self, void *aux)
  153 {
  154         int freq, ispburst, sbusburst;
  155         struct sbus_attach_args *sa = aux;
  156         struct isp_sbussoftc *sbc = (struct isp_sbussoftc *) self;
  157         struct ispsoftc *isp = &sbc->sbus_isp;
  158 
  159         printf(" for %s\n", sa->sa_name);
  160 
  161         sbc->sbus_bustag = sa->sa_bustag;
  162         if (sa->sa_nintr != 0)
  163                 sbc->sbus_pri = sa->sa_pri;
  164         sbc->sbus_mdvec = mdvec;
  165 
  166         if (sa->sa_npromvaddrs) {
  167                 sbus_promaddr_to_handle(sa->sa_bustag,
  168                         sa->sa_promvaddrs[0], &sbc->sbus_reg);
  169         } else {
  170                 if (sbus_bus_map(sa->sa_bustag, sa->sa_slot, sa->sa_offset,
  171                         sa->sa_size, 0, &sbc->sbus_reg) != 0) {
  172                         printf("%s: cannot map registers\n", self->dv_xname);
  173                         return;
  174                 }
  175         }
  176         sbc->sbus_node = sa->sa_node;
  177 
  178         freq = prom_getpropint(sa->sa_node, "clock-frequency", 0);
  179         if (freq) {
  180                 /*
  181                  * Convert from HZ to MHz, rounding up.
  182                  */
  183                 freq = (freq + 500000)/1000000;
  184 #if     0
  185                 printf("%s: %d MHz\n", self->dv_xname, freq);
  186 #endif
  187         }
  188         sbc->sbus_mdvec.dv_clock = freq;
  189 
  190         /*
  191          * Now figure out what the proper burst sizes, etc., to use.
  192          * Unfortunately, there is no ddi_dma_burstsizes here which
  193          * walks up the tree finding the limiting burst size node (if
  194          * any).
  195          */
  196         sbusburst = ((struct sbus_softc *)parent)->sc_burst;
  197         if (sbusburst == 0)
  198                 sbusburst = SBUS_BURST_32 - 1;
  199         ispburst = prom_getpropint(sa->sa_node, "burst-sizes", -1);
  200         if (ispburst == -1) {
  201                 ispburst = sbusburst;
  202         }
  203         ispburst &= sbusburst;
  204         ispburst &= ~(1 << 7);
  205         ispburst &= ~(1 << 6);
  206         sbc->sbus_mdvec.dv_conf1 =  0;
  207         if (ispburst & (1 << 5)) {
  208                 sbc->sbus_mdvec.dv_conf1 = BIU_SBUS_CONF1_FIFO_32;
  209         } else if (ispburst & (1 << 4)) {
  210                 sbc->sbus_mdvec.dv_conf1 = BIU_SBUS_CONF1_FIFO_16;
  211         } else if (ispburst & (1 << 3)) {
  212                 sbc->sbus_mdvec.dv_conf1 =
  213                     BIU_SBUS_CONF1_BURST8 | BIU_SBUS_CONF1_FIFO_8;
  214         }
  215         if (sbc->sbus_mdvec.dv_conf1) {
  216                 sbc->sbus_mdvec.dv_conf1 |= BIU_BURST_ENABLE;
  217         }
  218 
  219         /*
  220          * Some early versions of the PTI SBus adapter
  221          * would fail in trying to download (via poking)
  222          * FW. We give up on them.
  223          */
  224         if (strcmp("PTI,ptisp", sa->sa_name) == 0 ||
  225             strcmp("ptisp", sa->sa_name) == 0) {
  226                 sbc->sbus_mdvec.dv_ispfw = NULL;
  227         }
  228 
  229         isp->isp_mdvec = &sbc->sbus_mdvec;
  230         isp->isp_bustype = ISP_BT_SBUS;
  231         isp->isp_type = ISP_HA_SCSI_UNKNOWN;
  232         isp->isp_param = &sbc->sbus_dev;
  233         isp->isp_dmatag = sa->sa_dmatag;
  234         MEMZERO(isp->isp_param, sizeof (sdparam));
  235 
  236         sbc->sbus_poff[BIU_BLOCK >> _BLK_REG_SHFT] = BIU_REGS_OFF;
  237         sbc->sbus_poff[MBOX_BLOCK >> _BLK_REG_SHFT] = SBUS_MBOX_REGS_OFF;
  238         sbc->sbus_poff[SXP_BLOCK >> _BLK_REG_SHFT] = SBUS_SXP_REGS_OFF;
  239         sbc->sbus_poff[RISC_BLOCK >> _BLK_REG_SHFT] = SBUS_RISC_REGS_OFF;
  240         sbc->sbus_poff[DMA_BLOCK >> _BLK_REG_SHFT] = DMA_REGS_OFF;
  241 
  242         /* Establish interrupt channel */
  243         bus_intr_establish(sbc->sbus_bustag, sbc->sbus_pri, IPL_BIO,
  244             isp_sbus_intr, sbc);
  245         sbus_establish(&sbc->sbus_sd, &sbc->sbus_isp.isp_osinfo._dev);
  246 
  247         /*
  248          * Set up logging levels.
  249          */
  250 #ifdef  ISP_LOGDEFAULT
  251         isp->isp_dblev = ISP_LOGDEFAULT;
  252 #else
  253         isp->isp_dblev = ISP_LOGWARN|ISP_LOGERR;
  254         if (bootverbose)
  255                 isp->isp_dblev |= ISP_LOGCONFIG|ISP_LOGINFO;
  256 #ifdef  SCSIDEBUG
  257         isp->isp_dblev |= ISP_LOGDEBUG1|ISP_LOGDEBUG2;
  258 #endif
  259 #ifdef  DEBUG
  260         isp->isp_dblev |= ISP_LOGDEBUG0;
  261 #endif
  262 #endif
  263 
  264         isp->isp_confopts = self->dv_cfdata->cf_flags;
  265         isp->isp_role = ISP_DEFAULT_ROLES;
  266 
  267         /*
  268          * There's no tool on sparc to set NVRAM for ISPs, so ignore it.
  269          */
  270         isp->isp_confopts |= ISP_CFG_NONVRAM;
  271         ISP_LOCK(isp);
  272         isp->isp_osinfo.no_mbox_ints = 1;
  273         isp_reset(isp);
  274         if (isp->isp_state != ISP_RESETSTATE) {
  275                 ISP_UNLOCK(isp);
  276                 return;
  277         }
  278         ENABLE_INTS(isp);
  279         isp_init(isp);
  280         if (isp->isp_state != ISP_INITSTATE) {
  281                 isp_uninit(isp);
  282                 ISP_UNLOCK(isp);
  283                 return;
  284         }
  285 
  286         /*
  287          * do generic attach.
  288          */
  289         ISP_UNLOCK(isp);
  290         isp_attach(isp);
  291         if (isp->isp_state != ISP_RUNSTATE) {
  292                 ISP_LOCK(isp);
  293                 isp_uninit(isp);
  294                 ISP_UNLOCK(isp);
  295         }
  296 }
  297 
  298 
  299 static void
  300 isp_sbus_reset1(struct ispsoftc *isp)
  301 {
  302         if (isp->isp_osinfo.no_mbox_ints == 0) {
  303                 ENABLE_INTS(isp);
  304         }
  305 
  306 }
  307 
  308 static int
  309 isp_sbus_intr(void *arg)
  310 {
  311         u_int16_t isr, sema, mbox;
  312         struct ispsoftc *isp = arg;
  313 
  314         if (ISP_READ_ISR(isp, &isr, &sema, &mbox) == 0) {
  315                 isp->isp_intbogus++;
  316                 return (0);
  317         } else {
  318                 struct isp_sbussoftc *sbc = arg;
  319                 sbc->sbus_isp.isp_osinfo.onintstack = 1;
  320                 isp_intr(isp, isr, sema, mbox);
  321                 sbc->sbus_isp.isp_osinfo.onintstack = 0;
  322                 return (1);
  323         }
  324 }
  325 
  326 #define IspVirt2Off(a, x)       \
  327         (((struct isp_sbussoftc *)a)->sbus_poff[((x) & _BLK_REG_MASK) >> \
  328         _BLK_REG_SHFT] + ((x) & 0xff))
  329 
  330 #define BXR2(sbc, off)          \
  331         bus_space_read_2(sbc->sbus_bustag, sbc->sbus_reg, off)
  332 
  333 static int
  334 isp_sbus_rd_isr(struct ispsoftc *isp, u_int16_t *isrp,
  335     u_int16_t *semap, u_int16_t *mbp)
  336 {
  337         struct isp_sbussoftc *sbc = (struct isp_sbussoftc *) isp;
  338         u_int16_t isr, sema;
  339 
  340         isr = BXR2(sbc, IspVirt2Off(isp, BIU_ISR));
  341         sema = BXR2(sbc, IspVirt2Off(isp, BIU_SEMA));
  342         isp_prt(isp, ISP_LOGDEBUG3, "ISR 0x%x SEMA 0x%x", isr, sema);
  343         isr &= INT_PENDING_MASK(isp);
  344         sema &= BIU_SEMA_LOCK;
  345         if (isr == 0 && sema == 0) {
  346                 return (0);
  347         }
  348         *isrp = isr;
  349         if ((*semap = sema) != 0) {
  350                 *mbp = BXR2(sbc, IspVirt2Off(isp, OUTMAILBOX0));
  351         }
  352         return (1);
  353 }
  354 
  355 static u_int16_t
  356 isp_sbus_rd_reg(struct ispsoftc *isp, int regoff)
  357 {
  358         struct isp_sbussoftc *sbc = (struct isp_sbussoftc *) isp;
  359         int offset = sbc->sbus_poff[(regoff & _BLK_REG_MASK) >> _BLK_REG_SHFT];
  360         offset += (regoff & 0xff);
  361         return (bus_space_read_2(sbc->sbus_bustag, sbc->sbus_reg, offset));
  362 }
  363 
  364 static void
  365 isp_sbus_wr_reg(struct ispsoftc *isp, int regoff, u_int16_t val)
  366 {
  367         struct isp_sbussoftc *sbc = (struct isp_sbussoftc *) isp;
  368         int offset = sbc->sbus_poff[(regoff & _BLK_REG_MASK) >> _BLK_REG_SHFT];
  369         offset += (regoff & 0xff);
  370         bus_space_write_2(sbc->sbus_bustag, sbc->sbus_reg, offset, val);
  371 }
  372 
  373 static int
  374 isp_sbus_mbxdma(struct ispsoftc *isp)
  375 {
  376         struct isp_sbussoftc *sbc = (struct isp_sbussoftc *) isp;
  377         bus_dma_segment_t reqseg, rspseg;
  378         int reqrs, rsprs, i, progress;
  379         size_t n;
  380         bus_size_t len;
  381 
  382         if (isp->isp_rquest_dma)
  383                 return (0);
  384 
  385         n = isp->isp_maxcmds * sizeof (XS_T *);
  386         isp->isp_xflist = (XS_T **) malloc(n, M_DEVBUF, M_WAITOK);
  387         if (isp->isp_xflist == NULL) {
  388                 isp_prt(isp, ISP_LOGERR, "cannot alloc xflist array");
  389                 return (1);
  390         }
  391         MEMZERO(isp->isp_xflist, n);
  392         n = sizeof (bus_dmamap_t) * isp->isp_maxcmds;
  393         sbc->sbus_dmamap = (bus_dmamap_t *) malloc(n, M_DEVBUF, M_WAITOK);
  394         if (sbc->sbus_dmamap == NULL) {
  395                 free(isp->isp_xflist, M_DEVBUF);
  396                 isp->isp_xflist = NULL;
  397                 isp_prt(isp, ISP_LOGERR, "cannot alloc dmamap array");
  398                 return (1);
  399         }
  400         for (i = 0; i < isp->isp_maxcmds; i++) {
  401                 /* Allocate a DMA handle */
  402                 if (bus_dmamap_create(isp->isp_dmatag, MAXPHYS, 1, MAXPHYS, 0,
  403                     BUS_DMA_NOWAIT, &sbc->sbus_dmamap[i]) != 0) {
  404                         isp_prt(isp, ISP_LOGERR, "cmd DMA maps create error");
  405                         break;
  406                 }
  407         }
  408         if (i < isp->isp_maxcmds) {
  409                 while (--i >= 0) {
  410                         bus_dmamap_destroy(isp->isp_dmatag,
  411                             sbc->sbus_dmamap[i]);
  412                 }
  413                 free(isp->isp_xflist, M_DEVBUF);
  414                 free(sbc->sbus_dmamap, M_DEVBUF);
  415                 isp->isp_xflist = NULL;
  416                 sbc->sbus_dmamap = NULL;
  417                 return (1);
  418         }
  419 
  420         /*
  421          * Allocate and map the request and response queues
  422          */
  423         progress = 0;
  424         len = ISP_QUEUE_SIZE(RQUEST_QUEUE_LEN(isp));
  425         if (bus_dmamem_alloc(isp->isp_dmatag, len, 0, 0, &reqseg, 1, &reqrs,
  426             BUS_DMA_NOWAIT)) {
  427                 goto dmafail;
  428         }
  429         progress++;
  430         if (bus_dmamem_map(isp->isp_dmatag, &reqseg, reqrs, len,
  431             (caddr_t *)&isp->isp_rquest, BUS_DMA_NOWAIT|BUS_DMA_COHERENT)) {
  432                 goto dmafail;
  433         }
  434         progress++;
  435         if (bus_dmamap_create(isp->isp_dmatag, len, 1, len, 0, BUS_DMA_NOWAIT,
  436             &isp->isp_rqdmap) != 0) {
  437                 goto dmafail;
  438         }
  439         progress++;
  440         if (bus_dmamap_load(isp->isp_dmatag, isp->isp_rqdmap,
  441             isp->isp_rquest, len, NULL, BUS_DMA_NOWAIT) != 0) {
  442                 goto dmafail;
  443         }
  444         progress++;
  445         isp->isp_rquest_dma = isp->isp_rqdmap->dm_segs[0].ds_addr;
  446 
  447         len = ISP_QUEUE_SIZE(RESULT_QUEUE_LEN(isp));
  448         if (bus_dmamem_alloc(isp->isp_dmatag, len, 0, 0, &rspseg, 1, &rsprs,
  449             BUS_DMA_NOWAIT)) {
  450                 goto dmafail;
  451         }
  452         progress++;
  453         if (bus_dmamem_map(isp->isp_dmatag, &rspseg, rsprs, len,
  454             (caddr_t *)&isp->isp_result, BUS_DMA_NOWAIT|BUS_DMA_COHERENT)) {
  455                 goto dmafail;
  456         }
  457         progress++;
  458         if (bus_dmamap_create(isp->isp_dmatag, len, 1, len, 0, BUS_DMA_NOWAIT,
  459             &isp->isp_rsdmap) != 0) {
  460                 goto dmafail;
  461         }
  462         progress++;
  463         if (bus_dmamap_load(isp->isp_dmatag, isp->isp_rsdmap,
  464             isp->isp_result, len, NULL, BUS_DMA_NOWAIT) != 0) {
  465                 goto dmafail;
  466         }
  467         isp->isp_result_dma = isp->isp_rsdmap->dm_segs[0].ds_addr;
  468 
  469         return (0);
  470 
  471 dmafail:
  472         isp_prt(isp, ISP_LOGERR, "Mailbox DMA Setup Failure");
  473 
  474         if (progress >= 8) {
  475                 bus_dmamap_unload(isp->isp_dmatag, isp->isp_rsdmap);
  476         }
  477         if (progress >= 7) {
  478                 bus_dmamap_destroy(isp->isp_dmatag, isp->isp_rsdmap);
  479         }
  480         if (progress >= 6) {
  481                 bus_dmamem_unmap(isp->isp_dmatag,
  482                     isp->isp_result, ISP_QUEUE_SIZE(RESULT_QUEUE_LEN(isp)));
  483         }
  484         if (progress >= 5) {
  485                 bus_dmamem_free(isp->isp_dmatag, &rspseg, rsprs);
  486         }
  487 
  488         if (progress >= 4) {
  489                 bus_dmamap_unload(isp->isp_dmatag, isp->isp_rqdmap);
  490         }
  491         if (progress >= 3) {
  492                 bus_dmamap_destroy(isp->isp_dmatag, isp->isp_rqdmap);
  493         }
  494         if (progress >= 2) {
  495                 bus_dmamem_unmap(isp->isp_dmatag,
  496                     isp->isp_rquest, ISP_QUEUE_SIZE(RQUEST_QUEUE_LEN(isp)));
  497         }
  498         if (progress >= 1) {
  499                 bus_dmamem_free(isp->isp_dmatag, &reqseg, reqrs);
  500         }
  501 
  502         for (i = 0; i < isp->isp_maxcmds; i++) {
  503                 bus_dmamap_destroy(isp->isp_dmatag, sbc->sbus_dmamap[i]);
  504         }
  505         free(sbc->sbus_dmamap, M_DEVBUF);
  506         free(isp->isp_xflist, M_DEVBUF);
  507         isp->isp_xflist = NULL;
  508         sbc->sbus_dmamap = NULL;
  509         return (1);
  510 }
  511 
  512 /*
  513  * Map a DMA request.
  514  * We're guaranteed that rq->req_handle is a value from 1 to isp->isp_maxcmds.
  515  */
  516 
  517 static int
  518 isp_sbus_dmasetup(struct ispsoftc *isp, XS_T *xs, ispreq_t *rq,
  519     u_int16_t *nxtip, u_int16_t optr)
  520 {
  521         struct isp_sbussoftc *sbc = (struct isp_sbussoftc *) isp;
  522         bus_dmamap_t dmap;
  523         ispreq_t *qep;
  524         int error, cansleep = (xs->xs_control & XS_CTL_NOSLEEP) == 0;
  525         int in = (xs->xs_control & XS_CTL_DATA_IN) != 0;
  526 
  527         qep = (ispreq_t *) ISP_QUEUE_ENTRY(isp->isp_rquest, isp->isp_reqidx);
  528         if (xs->datalen == 0) {
  529                 rq->req_seg_count = 1;
  530                 goto mbxsync;
  531         }
  532 
  533         dmap = sbc->sbus_dmamap[isp_handle_index(rq->req_handle)];
  534         if (dmap->dm_nsegs != 0) {
  535                 panic("%s: DMA map already allocated", isp->isp_name);
  536                 /* NOTREACHED */
  537         }
  538         error = bus_dmamap_load(isp->isp_dmatag, dmap, xs->data, xs->datalen,
  539             NULL, (cansleep ? BUS_DMA_WAITOK : BUS_DMA_NOWAIT) |
  540             BUS_DMA_STREAMING);
  541         if (error != 0) {
  542                 XS_SETERR(xs, HBA_BOTCH);
  543                 if (error == EAGAIN || error == ENOMEM)
  544                         return (CMD_EAGAIN);
  545                 else
  546                         return (CMD_COMPLETE);
  547         }
  548 
  549         bus_dmamap_sync(isp->isp_dmatag, dmap, 0, xs->datalen,
  550             in? BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE);
  551 
  552         if (in) {
  553                 rq->req_flags |= REQFLAG_DATA_IN;
  554         } else {
  555                 rq->req_flags |= REQFLAG_DATA_OUT;
  556         }
  557 
  558         if (XS_CDBLEN(xs) > 12) {
  559                 u_int16_t onxti;
  560                 ispcontreq_t local, *crq = &local, *cqe;
  561 
  562                 onxti = *nxtip;
  563                 cqe = (ispcontreq_t *) ISP_QUEUE_ENTRY(isp->isp_rquest, onxti);
  564                 *nxtip = ISP_NXT_QENTRY(onxti, RQUEST_QUEUE_LEN(isp));
  565                 if (*nxtip == optr) {
  566                         isp_prt(isp, ISP_LOGDEBUG0, "Request Queue Overflow++");
  567                         bus_dmamap_unload(isp->isp_dmatag, dmap);
  568                         XS_SETERR(xs, HBA_BOTCH);
  569                         return (CMD_EAGAIN);
  570                 }
  571                 rq->req_seg_count = 2;
  572                 MEMZERO((void *)crq, sizeof (*crq));
  573                 crq->req_header.rqs_entry_count = 1;
  574                 crq->req_header.rqs_entry_type = RQSTYPE_DATASEG;  
  575                 crq->req_dataseg[0].ds_count = xs->datalen;
  576                 crq->req_dataseg[0].ds_base = dmap->dm_segs[0].ds_addr;
  577                 isp_put_cont_req(isp, crq, cqe);
  578                 MEMORYBARRIER(isp, SYNC_REQUEST, onxti, QENTRY_LEN);
  579         } else {
  580                 rq->req_seg_count = 1;
  581                 rq->req_dataseg[0].ds_count = xs->datalen;
  582                 rq->req_dataseg[0].ds_base = dmap->dm_segs[0].ds_addr;
  583         }
  584 
  585 mbxsync:
  586         if (XS_CDBLEN(xs) > 12) {
  587                 isp_put_extended_request(isp,
  588                     (ispextreq_t *)rq, (ispextreq_t *) qep);
  589         } else {
  590                 isp_put_request(isp, rq, qep);
  591         }
  592         return (CMD_QUEUED);
  593 }
  594 
  595 static void
  596 isp_sbus_dmateardown(struct ispsoftc *isp, XS_T *xs, u_int16_t handle)
  597 {
  598         struct isp_sbussoftc *sbc = (struct isp_sbussoftc *) isp;
  599         bus_dmamap_t dmap;
  600 
  601         dmap = sbc->sbus_dmamap[isp_handle_index(handle)];
  602 
  603         if (dmap->dm_nsegs == 0) {
  604                 panic("%s: DMA map not already allocated", isp->isp_name);
  605                 /* NOTREACHED */
  606         }
  607         bus_dmamap_sync(isp->isp_dmatag, dmap, 0,
  608             xs->datalen, (xs->xs_control & XS_CTL_DATA_IN)?
  609             BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);
  610         bus_dmamap_unload(isp->isp_dmatag, dmap);
  611 }

Cache object: 8fdb6c8f0f051a7a1a4b0e7a607915f2


[ 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.