root/dev/sbus/isp_sbus.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. isp_match
  2. isp_sbus_attach
  3. isp_sbus_intr
  4. isp_sbus_rd_isr
  5. isp_sbus_rd_reg
  6. isp_sbus_wr_reg
  7. isp_sbus_mbxdma
  8. isp_sbus_dmasetup
  9. isp_sbus_dmateardown

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

/* [<][>][^][v][top][bottom][index][help] */