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/ic/icp.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: icp.c,v 1.12 2003/10/29 00:48:15 mycroft Exp $ */
    2 
    3 /*-
    4  * Copyright (c) 2002, 2003 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, and by Jason R. Thorpe of Wasabi Systems, Inc.
    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) 1999, 2000 Niklas Hallqvist.  All rights reserved.
   41  *
   42  * Redistribution and use in source and binary forms, with or without
   43  * modification, are permitted provided that the following conditions
   44  * are met:
   45  * 1. Redistributions of source code must retain the above copyright
   46  *    notice, this list of conditions and the following disclaimer.
   47  * 2. Redistributions in binary form must reproduce the above copyright
   48  *    notice, this list of conditions and the following disclaimer in the
   49  *    documentation and/or other materials provided with the distribution.
   50  * 3. All advertising materials mentioning features or use of this software
   51  *    must display the following acknowledgement:
   52  *      This product includes software developed by Niklas Hallqvist.
   53  * 4. The name of the author may not be used to endorse or promote products
   54  *    derived from this software without specific prior written permission.
   55  *
   56  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   57  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   58  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   59  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   60  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   61   * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   62  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   63  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   64  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   65  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   66  *
   67  * from OpenBSD: gdt_common.c,v 1.12 2001/07/04 06:43:18 niklas Exp
   68  */
   69 
   70 /*
   71  * This driver would not have written if it was not for the hardware donations
   72  * from both ICP-Vortex and Öko.neT.  I want to thank them for their support.
   73  *
   74  * Re-worked for NetBSD by Andrew Doran.  Test hardware kindly supplied by
   75  * Intel.
   76  *
   77  * Support for the ICP-Vortex management tools added by
   78  * Jason R. Thorpe of Wasabi Systems, Inc., based on code
   79  * provided by Achim Leubner <achim.leubner@intel.com>.
   80  *
   81  * Additional support for dynamic rescan of cacheservice drives by
   82  * Jason R. Thorpe of Wasabi Systems, Inc.
   83  */
   84 
   85 #include <sys/cdefs.h>
   86 __KERNEL_RCSID(0, "$NetBSD: icp.c,v 1.12 2003/10/29 00:48:15 mycroft Exp $");
   87 
   88 #include <sys/param.h>
   89 #include <sys/systm.h>
   90 #include <sys/kernel.h>
   91 #include <sys/device.h>
   92 #include <sys/queue.h>
   93 #include <sys/proc.h>
   94 #include <sys/buf.h>
   95 #include <sys/endian.h>
   96 #include <sys/malloc.h>
   97 #include <sys/disk.h>
   98 
   99 #include <uvm/uvm_extern.h>
  100 
  101 #include <machine/bswap.h>
  102 #include <machine/bus.h>
  103 
  104 #include <dev/pci/pcireg.h>
  105 #include <dev/pci/pcivar.h>
  106 #include <dev/pci/pcidevs.h>
  107 
  108 #include <dev/ic/icpreg.h>
  109 #include <dev/ic/icpvar.h>
  110 
  111 #include <dev/scsipi/scsipi_all.h>
  112 #include <dev/scsipi/scsiconf.h>
  113 
  114 int     icp_async_event(struct icp_softc *, int);
  115 void    icp_ccb_submit(struct icp_softc *icp, struct icp_ccb *ic);
  116 void    icp_chain(struct icp_softc *);
  117 int     icp_print(void *, const char *);
  118 int     icp_submatch(struct device *, struct cfdata *, void *);
  119 void    icp_watchdog(void *);
  120 void    icp_ucmd_intr(struct icp_ccb *);
  121 void    icp_recompute_openings(struct icp_softc *);
  122 
  123 int     icp_count;      /* total # of controllers, for ioctl interface */
  124 
  125 /*
  126  * Statistics for the ioctl interface to query.
  127  *
  128  * XXX Global.  They should probably be made per-controller
  129  * XXX at some point.
  130  */
  131 gdt_statist_t icp_stats;
  132 
  133 int
  134 icp_init(struct icp_softc *icp, const char *intrstr)
  135 {
  136         struct icp_attach_args icpa;
  137         struct icp_binfo binfo;
  138         struct icp_ccb *ic;
  139         u_int16_t cdev_cnt;
  140         int i, j, state, feat, nsegs, rv;
  141 
  142         state = 0;
  143 
  144         if (intrstr != NULL)
  145                 aprint_normal("%s: interrupting at %s\n", icp->icp_dv.dv_xname,
  146                     intrstr);
  147 
  148         SIMPLEQ_INIT(&icp->icp_ccb_queue);
  149         SIMPLEQ_INIT(&icp->icp_ccb_freelist);
  150         SIMPLEQ_INIT(&icp->icp_ucmd_queue);
  151         callout_init(&icp->icp_wdog_callout);
  152 
  153         /*
  154          * Allocate a scratch area.
  155          */
  156         if (bus_dmamap_create(icp->icp_dmat, ICP_SCRATCH_SIZE, 1,
  157             ICP_SCRATCH_SIZE, 0, BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW,
  158             &icp->icp_scr_dmamap) != 0) {
  159                 aprint_error("%s: cannot create scratch dmamap\n",
  160                     icp->icp_dv.dv_xname);
  161                 return (1);
  162         }
  163         state++;
  164 
  165         if (bus_dmamem_alloc(icp->icp_dmat, ICP_SCRATCH_SIZE, PAGE_SIZE, 0,
  166             icp->icp_scr_seg, 1, &nsegs, BUS_DMA_NOWAIT) != 0) {
  167                 aprint_error("%s: cannot alloc scratch dmamem\n",
  168                     icp->icp_dv.dv_xname);
  169                 goto bail_out;
  170         }
  171         state++;
  172 
  173         if (bus_dmamem_map(icp->icp_dmat, icp->icp_scr_seg, nsegs,
  174             ICP_SCRATCH_SIZE, &icp->icp_scr, 0)) {
  175                 aprint_error("%s: cannot map scratch dmamem\n",
  176                     icp->icp_dv.dv_xname);
  177                 goto bail_out;
  178         }
  179         state++;
  180 
  181         if (bus_dmamap_load(icp->icp_dmat, icp->icp_scr_dmamap, icp->icp_scr,
  182             ICP_SCRATCH_SIZE, NULL, BUS_DMA_NOWAIT)) {
  183                 aprint_error("%s: cannot load scratch dmamap\n",
  184                     icp->icp_dv.dv_xname);
  185                 goto bail_out;
  186         }
  187         state++;
  188 
  189         /*
  190          * Allocate and initialize the command control blocks.
  191          */
  192         ic = malloc(sizeof(*ic) * ICP_NCCBS, M_DEVBUF, M_NOWAIT | M_ZERO);
  193         if ((icp->icp_ccbs = ic) == NULL) {
  194                 aprint_error("%s: malloc() failed\n", icp->icp_dv.dv_xname);
  195                 goto bail_out;
  196         }
  197         state++;
  198 
  199         for (i = 0; i < ICP_NCCBS; i++, ic++) {
  200                 /*
  201                  * The first two command indexes have special meanings, so
  202                  * we can't use them.
  203                  */
  204                 ic->ic_ident = i + 2;
  205                 rv = bus_dmamap_create(icp->icp_dmat, ICP_MAX_XFER,
  206                     ICP_MAXSG, ICP_MAX_XFER, 0,
  207                     BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW,
  208                     &ic->ic_xfer_map);
  209                 if (rv != 0)
  210                         break;
  211                 icp->icp_nccbs++;
  212                 icp_ccb_free(icp, ic);
  213         }
  214 #ifdef DIAGNOSTIC
  215         if (icp->icp_nccbs != ICP_NCCBS)
  216                 aprint_error("%s: %d/%d CCBs usable\n", icp->icp_dv.dv_xname,
  217                     icp->icp_nccbs, ICP_NCCBS);
  218 #endif
  219 
  220         /*
  221          * Initalize the controller.
  222          */
  223         if (!icp_cmd(icp, ICP_SCREENSERVICE, ICP_INIT, 0, 0, 0)) {
  224                 aprint_error("%s: screen service init error %d\n",
  225                     icp->icp_dv.dv_xname, icp->icp_status);
  226                 goto bail_out;
  227         }
  228 
  229         if (!icp_cmd(icp, ICP_CACHESERVICE, ICP_INIT, ICP_LINUX_OS, 0, 0)) {
  230                 aprint_error("%s: cache service init error %d\n",
  231                     icp->icp_dv.dv_xname, icp->icp_status);
  232                 goto bail_out;
  233         }
  234 
  235         icp_cmd(icp, ICP_CACHESERVICE, ICP_UNFREEZE_IO, 0, 0, 0);
  236 
  237         if (!icp_cmd(icp, ICP_CACHESERVICE, ICP_MOUNT, 0xffff, 1, 0)) {
  238                 aprint_error("%s: cache service mount error %d\n",
  239                     icp->icp_dv.dv_xname, icp->icp_status);
  240                 goto bail_out;
  241         }
  242 
  243         if (!icp_cmd(icp, ICP_CACHESERVICE, ICP_INIT, ICP_LINUX_OS, 0, 0)) {
  244                 aprint_error("%s: cache service post-mount init error %d\n",
  245                     icp->icp_dv.dv_xname, icp->icp_status);
  246                 goto bail_out;
  247         }
  248         cdev_cnt = (u_int16_t)icp->icp_info;
  249         icp->icp_fw_vers = icp->icp_service;
  250 
  251         if (!icp_cmd(icp, ICP_SCSIRAWSERVICE, ICP_INIT, 0, 0, 0)) {
  252                 aprint_error("%s: raw service init error %d\n",
  253                     icp->icp_dv.dv_xname, icp->icp_status);
  254                 goto bail_out;
  255         }
  256 
  257         /*
  258          * Set/get raw service features (scatter/gather).
  259          */
  260         feat = 0;
  261         if (icp_cmd(icp, ICP_SCSIRAWSERVICE, ICP_SET_FEAT, ICP_SCATTER_GATHER,
  262             0, 0))
  263                 if (icp_cmd(icp, ICP_SCSIRAWSERVICE, ICP_GET_FEAT, 0, 0, 0))
  264                         feat = icp->icp_info;
  265 
  266         if ((feat & ICP_SCATTER_GATHER) == 0) {
  267 #ifdef DIAGNOSTIC
  268                 aprint_normal(
  269                     "%s: scatter/gather not supported (raw service)\n",
  270                     icp->icp_dv.dv_xname);
  271 #endif
  272         } else
  273                 icp->icp_features |= ICP_FEAT_RAWSERVICE;
  274 
  275         /*
  276          * Set/get cache service features (scatter/gather).
  277          */
  278         feat = 0;
  279         if (icp_cmd(icp, ICP_CACHESERVICE, ICP_SET_FEAT, 0,
  280             ICP_SCATTER_GATHER, 0))
  281                 if (icp_cmd(icp, ICP_CACHESERVICE, ICP_GET_FEAT, 0, 0, 0))
  282                         feat = icp->icp_info;
  283 
  284         if ((feat & ICP_SCATTER_GATHER) == 0) {
  285 #ifdef DIAGNOSTIC
  286                 aprint_normal(
  287                     "%s: scatter/gather not supported (cache service)\n",
  288                     icp->icp_dv.dv_xname);
  289 #endif
  290         } else
  291                 icp->icp_features |= ICP_FEAT_CACHESERVICE;
  292 
  293         /*
  294          * Pull some information from the board and dump.
  295          */
  296         if (!icp_cmd(icp, ICP_CACHESERVICE, ICP_IOCTL, ICP_BOARD_INFO,
  297             ICP_INVALID_CHANNEL, sizeof(struct icp_binfo))) {
  298                 aprint_error("%s: unable to retrive board info\n",
  299                     icp->icp_dv.dv_xname);
  300                 goto bail_out;
  301         }
  302         memcpy(&binfo, icp->icp_scr, sizeof(binfo));
  303 
  304         aprint_normal(
  305             "%s: model <%s>, firmware <%s>, %d channel(s), %dMB memory\n",
  306             icp->icp_dv.dv_xname, binfo.bi_type_string, binfo.bi_raid_string,
  307             binfo.bi_chan_count, le32toh(binfo.bi_memsize) >> 20);
  308 
  309         /*
  310          * Determine the number of devices, and number of openings per
  311          * device.
  312          */
  313         if (icp->icp_features & ICP_FEAT_CACHESERVICE) {
  314                 for (j = 0; j < cdev_cnt && j < ICP_MAX_HDRIVES; j++) {
  315                         if (!icp_cmd(icp, ICP_CACHESERVICE, ICP_INFO, j, 0,
  316                             0))
  317                                 continue;
  318 
  319                         icp->icp_cdr[j].cd_size = icp->icp_info;
  320                         if (icp->icp_cdr[j].cd_size != 0)
  321                                 icp->icp_ndevs++;
  322 
  323                         if (icp_cmd(icp, ICP_CACHESERVICE, ICP_DEVTYPE, j, 0,
  324                             0))
  325                                 icp->icp_cdr[j].cd_type = icp->icp_info;
  326                 }
  327         }
  328 
  329         if (icp->icp_features & ICP_FEAT_RAWSERVICE) {
  330                 icp->icp_nchan = binfo.bi_chan_count;
  331                 icp->icp_ndevs += icp->icp_nchan;
  332         }
  333 
  334         icp_recompute_openings(icp);
  335 
  336         /*
  337          * Attach SCSI channels.
  338          */
  339         if (icp->icp_features & ICP_FEAT_RAWSERVICE) {
  340                 struct icp_ioc_version *iv;
  341                 struct icp_rawioc *ri;
  342                 struct icp_getch *gc;
  343 
  344                 iv = (struct icp_ioc_version *)icp->icp_scr;
  345                 iv->iv_version = htole32(ICP_IOC_NEWEST);
  346                 iv->iv_listents = ICP_MAXBUS;
  347                 iv->iv_firstchan = 0;
  348                 iv->iv_lastchan = ICP_MAXBUS - 1;
  349                 iv->iv_listoffset = htole32(sizeof(*iv));
  350 
  351                 if (icp_cmd(icp, ICP_CACHESERVICE, ICP_IOCTL,
  352                     ICP_IOCHAN_RAW_DESC, ICP_INVALID_CHANNEL,
  353                     sizeof(*iv) + ICP_MAXBUS * sizeof(*ri))) {
  354                         ri = (struct icp_rawioc *)(iv + 1);
  355                         for (j = 0; j < binfo.bi_chan_count; j++, ri++)
  356                                 icp->icp_bus_id[j] = ri->ri_procid;
  357                 } else {
  358                         /*
  359                          * Fall back to the old method.
  360                          */
  361                         gc = (struct icp_getch *)icp->icp_scr;
  362 
  363                         for (j = 0; j < binfo.bi_chan_count; j++) {
  364                                 if (!icp_cmd(icp, ICP_CACHESERVICE, ICP_IOCTL,
  365                                     ICP_SCSI_CHAN_CNT | ICP_L_CTRL_PATTERN,
  366                                     ICP_IO_CHANNEL | ICP_INVALID_CHANNEL,
  367                                     sizeof(*gc))) {
  368                                         aprint_error(
  369                                             "%s: unable to get chan info",
  370                                             icp->icp_dv.dv_xname);
  371                                         goto bail_out;
  372                                 }
  373                                 icp->icp_bus_id[j] = gc->gc_scsiid;
  374                         }
  375                 }
  376 
  377                 for (j = 0; j < binfo.bi_chan_count; j++) {
  378                         if (icp->icp_bus_id[j] > ICP_MAXID_FC)
  379                                 icp->icp_bus_id[j] = ICP_MAXID_FC;
  380 
  381                         icpa.icpa_unit = j + ICPA_UNIT_SCSI;
  382                         icp->icp_children[icpa.icpa_unit] =
  383                             config_found_sm(&icp->icp_dv, &icpa, icp_print,
  384                             icp_submatch);
  385                 }
  386         }
  387 
  388         /*
  389          * Attach cache devices.
  390          */
  391         if (icp->icp_features & ICP_FEAT_CACHESERVICE) {
  392                 for (j = 0; j < cdev_cnt && j < ICP_MAX_HDRIVES; j++) {
  393                         if (icp->icp_cdr[j].cd_size == 0)
  394                                 continue;
  395                 
  396                         icpa.icpa_unit = j;
  397                         icp->icp_children[icpa.icpa_unit] =
  398                             config_found_sm(&icp->icp_dv, &icpa, icp_print,
  399                             icp_submatch);
  400                 }
  401         }
  402 
  403         /*
  404          * Start the watchdog.
  405          */
  406         icp_watchdog(icp);
  407 
  408         /*
  409          * Count the controller, and we're done!
  410          */
  411         icp_count++;
  412 
  413         return (0);
  414 
  415  bail_out:
  416         if (state > 4)
  417                 for (j = 0; j < i; j++)
  418                         bus_dmamap_destroy(icp->icp_dmat,
  419                             icp->icp_ccbs[j].ic_xfer_map);
  420         if (state > 3)
  421                 free(icp->icp_ccbs, M_DEVBUF);
  422         if (state > 2)
  423                 bus_dmamap_unload(icp->icp_dmat, icp->icp_scr_dmamap);
  424         if (state > 1)
  425                 bus_dmamem_unmap(icp->icp_dmat, icp->icp_scr,
  426                     ICP_SCRATCH_SIZE);
  427         if (state > 0)
  428                 bus_dmamem_free(icp->icp_dmat, icp->icp_scr_seg, nsegs);
  429         bus_dmamap_destroy(icp->icp_dmat, icp->icp_scr_dmamap);
  430 
  431         return (1);
  432 }
  433 
  434 void
  435 icp_register_servicecb(struct icp_softc *icp, int unit,
  436     const struct icp_servicecb *cb)
  437 {
  438 
  439         icp->icp_servicecb[unit] = cb;
  440 }
  441 
  442 void
  443 icp_rescan(struct icp_softc *icp, int unit)
  444 {
  445         struct icp_attach_args icpa;
  446         u_int newsize, newtype;
  447 
  448         /*
  449          * NOTE: It is very important that the queue be frozen and not
  450          * commands running when this is called.  The ioctl mutex must
  451          * also be held.
  452          */
  453 
  454         KASSERT(icp->icp_qfreeze != 0);
  455         KASSERT(icp->icp_running == 0);
  456         KASSERT(unit < ICP_MAX_HDRIVES);
  457 
  458         if (!icp_cmd(icp, ICP_CACHESERVICE, ICP_INFO, unit, 0, 0)) {
  459 #ifdef ICP_DEBUG
  460                 printf("%s: rescan: unit %d ICP_INFO failed -> 0x%04x\n",
  461                     icp->icp_dv.dv_xname, unit, icp->icp_status);
  462 #endif
  463                 goto gone;
  464         }
  465         if ((newsize = icp->icp_info) == 0) {
  466 #ifdef ICP_DEBUG
  467                 printf("%s: rescan: unit %d has zero size\n",
  468                     icp->icp_dv.dv_xname, unit);
  469 #endif
  470  gone:
  471                 /*
  472                  * Host drive is no longer present; detach if a child
  473                  * is currently there.
  474                  */
  475                 if (icp->icp_cdr[unit].cd_size != 0)
  476                         icp->icp_ndevs--;
  477                 icp->icp_cdr[unit].cd_size = 0;
  478                 if (icp->icp_children[unit] != NULL) {
  479                         (void) config_detach(icp->icp_children[unit],
  480                             DETACH_FORCE);
  481                         icp->icp_children[unit] = NULL;
  482                 }
  483                 return;
  484         }
  485 
  486         if (icp_cmd(icp, ICP_CACHESERVICE, ICP_DEVTYPE, unit, 0, 0))
  487                 newtype = icp->icp_info;
  488         else {
  489 #ifdef ICP_DEBUG
  490                 printf("%s: rescan: unit %d ICP_DEVTYPE failed\n",
  491                     icp->icp_dv.dv_xname, unit);
  492 #endif
  493                 newtype = 0;    /* XXX? */
  494         }
  495 
  496 #ifdef ICP_DEBUG
  497         printf("%s: rescan: unit %d old %u/%u, new %u/%u\n",
  498             icp->icp_dv.dv_xname, unit, icp->icp_cdr[unit].cd_size,
  499             icp->icp_cdr[unit].cd_type, newsize, newtype);
  500 #endif
  501 
  502         /*
  503          * If the type or size changed, detach any old child (if it exists)
  504          * and attach a new one.
  505          */
  506         if (icp->icp_children[unit] == NULL ||
  507             newsize != icp->icp_cdr[unit].cd_size ||
  508             newtype != icp->icp_cdr[unit].cd_type) {
  509                 if (icp->icp_cdr[unit].cd_size == 0)
  510                         icp->icp_ndevs++;
  511                 icp->icp_cdr[unit].cd_size = newsize;
  512                 icp->icp_cdr[unit].cd_type = newtype;
  513                 if (icp->icp_children[unit] != NULL)
  514                         (void) config_detach(icp->icp_children[unit],
  515                             DETACH_FORCE);
  516 
  517                 icpa.icpa_unit = unit;
  518                 icp->icp_children[unit] = config_found_sm(&icp->icp_dv, &icpa,
  519                     icp_print, icp_submatch);
  520         }
  521 
  522         icp_recompute_openings(icp);
  523 }
  524 
  525 void
  526 icp_rescan_all(struct icp_softc *icp)
  527 {
  528         int unit;
  529         u_int16_t cdev_cnt;
  530 
  531         /*
  532          * This is the old method of rescanning the host drives.  We
  533          * start by reinitializing the cache service.
  534          */
  535         if (!icp_cmd(icp, ICP_CACHESERVICE, ICP_INIT, ICP_LINUX_OS, 0, 0)) {
  536                 printf("%s: unable to re-initialize cache service for rescan\n",
  537                     icp->icp_dv.dv_xname);
  538                 return;
  539         }
  540         cdev_cnt = (u_int16_t) icp->icp_info;
  541 
  542         /* For each host drive, do the new-style rescan. */
  543         for (unit = 0; unit < cdev_cnt && unit < ICP_MAX_HDRIVES; unit++)
  544                 icp_rescan(icp, unit);
  545 
  546         /* Now detach anything in the slots after cdev_cnt. */
  547         for (; unit < ICP_MAX_HDRIVES; unit++) {
  548                 if (icp->icp_cdr[unit].cd_size != 0) {
  549 #ifdef ICP_DEBUG
  550                         printf("%s: rescan all: unit %d < new cdev_cnt (%d)\n",
  551                             icp->icp_dv.dv_xname, unit, cdev_cnt);
  552 #endif
  553                         icp->icp_ndevs--;
  554                         icp->icp_cdr[unit].cd_size = 0;
  555                         if (icp->icp_children[unit] != NULL) {
  556                                 (void) config_detach(icp->icp_children[unit],
  557                                     DETACH_FORCE);
  558                                 icp->icp_children[unit] = NULL;
  559                         }
  560                 }
  561         }
  562 
  563         icp_recompute_openings(icp);
  564 }
  565 
  566 void
  567 icp_recompute_openings(struct icp_softc *icp)
  568 {
  569         int unit, openings;
  570 
  571         if (icp->icp_ndevs != 0)
  572                 openings =
  573                     (icp->icp_nccbs - ICP_NCCB_RESERVE) / icp->icp_ndevs;
  574         else
  575                 openings = 0;
  576         if (openings == icp->icp_openings)
  577                 return;
  578         icp->icp_openings = openings;
  579 
  580 #ifdef ICP_DEBUG
  581         printf("%s: %d device%s, %d openings per device\n",
  582             icp->icp_dv.dv_xname, icp->icp_ndevs,
  583             icp->icp_ndevs == 1 ? "" : "s", icp->icp_openings);
  584 #endif
  585 
  586         for (unit = 0; unit < ICP_MAX_HDRIVES + ICP_MAXBUS; unit++) {
  587                 if (icp->icp_children[unit] != NULL)
  588                         (*icp->icp_servicecb[unit]->iscb_openings)(
  589                             icp->icp_children[unit], icp->icp_openings);
  590         }
  591 }
  592 
  593 void
  594 icp_watchdog(void *cookie)
  595 {
  596         struct icp_softc *icp;
  597         int s;
  598 
  599         icp = cookie;
  600 
  601         s = splbio();
  602         icp_intr(icp);
  603         if (ICP_HAS_WORK(icp))
  604                 icp_ccb_enqueue(icp, NULL);
  605         splx(s);
  606 
  607         callout_reset(&icp->icp_wdog_callout, hz * ICP_WATCHDOG_FREQ,
  608             icp_watchdog, icp);
  609 }
  610 
  611 int
  612 icp_print(void *aux, const char *pnp)
  613 {
  614         struct icp_attach_args *icpa;
  615         const char *str;
  616 
  617         icpa = (struct icp_attach_args *)aux;
  618 
  619         if (pnp != NULL) {
  620                 if (icpa->icpa_unit < ICPA_UNIT_SCSI)
  621                         str = "block device";
  622                 else
  623                         str = "SCSI channel";
  624                 aprint_normal("%s at %s", str, pnp);
  625         }
  626         aprint_normal(" unit %d", icpa->icpa_unit);
  627 
  628         return (UNCONF);
  629 }
  630 
  631 int
  632 icp_submatch(struct device *parent, struct cfdata *cf, void *aux)
  633 {
  634         struct icp_attach_args *icpa;
  635 
  636         icpa = (struct icp_attach_args *)aux;
  637 
  638         if (cf->icpacf_unit != ICPCF_UNIT_DEFAULT &&
  639             cf->icpacf_unit != icpa->icpa_unit)
  640                 return (0);
  641 
  642         return (config_match(parent, cf, aux));
  643 }
  644 
  645 int
  646 icp_async_event(struct icp_softc *icp, int service)
  647 {
  648 
  649         if (service == ICP_SCREENSERVICE) {
  650                 if (icp->icp_status == ICP_S_MSG_REQUEST) {
  651                         /* XXX */
  652                 }
  653         } else {
  654                 if ((icp->icp_fw_vers & 0xff) >= 0x1a) {
  655                         icp->icp_evt.size = 0;
  656                         icp->icp_evt.eu.async.ionode = icp->icp_dv.dv_unit;
  657                         icp->icp_evt.eu.async.status = icp->icp_status;
  658                         /*
  659                          * Severity and event string are filled in by the
  660                          * hardware interface interrupt handler.
  661                          */
  662                         printf("%s: %s\n", icp->icp_dv.dv_xname,
  663                             icp->icp_evt.event_string);
  664                 } else {
  665                         icp->icp_evt.size = sizeof(icp->icp_evt.eu.async);
  666                         icp->icp_evt.eu.async.ionode = icp->icp_dv.dv_unit;
  667                         icp->icp_evt.eu.async.service = service;
  668                         icp->icp_evt.eu.async.status = icp->icp_status;
  669                         icp->icp_evt.eu.async.info = icp->icp_info;
  670                         /* XXXJRT FIX THIS */
  671                         *(u_int32_t *) icp->icp_evt.eu.async.scsi_coord = 
  672                             icp->icp_info2;
  673                 }
  674                 icp_store_event(icp, GDT_ES_ASYNC, service, &icp->icp_evt);
  675         }
  676 
  677         return (0);
  678 }
  679 
  680 int
  681 icp_intr(void *cookie)
  682 {
  683         struct icp_softc *icp;
  684         struct icp_intr_ctx ctx;
  685         struct icp_ccb *ic;
  686 
  687         icp = cookie;
  688 
  689         ctx.istatus = (*icp->icp_get_status)(icp);
  690         if (!ctx.istatus) {
  691                 icp->icp_status = ICP_S_NO_STATUS;
  692                 return (0);
  693         }
  694 
  695         (*icp->icp_intr)(icp, &ctx);
  696 
  697         icp->icp_status = ctx.cmd_status;
  698         icp->icp_service = ctx.service;
  699         icp->icp_info = ctx.info;
  700         icp->icp_info2 = ctx.info2;
  701 
  702         switch (ctx.istatus) {
  703         case ICP_ASYNCINDEX:
  704                 icp_async_event(icp, ctx.service);
  705                 return (1);
  706 
  707         case ICP_SPEZINDEX:
  708                 printf("%s: uninitialized or unknown service (%d/%d)\n",
  709                     icp->icp_dv.dv_xname, ctx.info, ctx.info2);
  710                 icp->icp_evt.size = sizeof(icp->icp_evt.eu.driver);
  711                 icp->icp_evt.eu.driver.ionode = icp->icp_dv.dv_unit;
  712                 icp_store_event(icp, GDT_ES_DRIVER, 4, &icp->icp_evt);
  713                 return (1);
  714         }
  715 
  716         if ((ctx.istatus - 2) > icp->icp_nccbs)
  717                 panic("icp_intr: bad command index returned");
  718 
  719         ic = &icp->icp_ccbs[ctx.istatus - 2];
  720         ic->ic_status = icp->icp_status;
  721 
  722         if ((ic->ic_flags & IC_ALLOCED) == 0) {
  723                 /* XXX ICP's "iir" driver just sends an event here. */
  724                 panic("icp_intr: inactive CCB identified");
  725         }
  726 
  727         /*
  728          * Try to protect ourselves from the running command count already
  729          * being 0 (e.g. if a polled command times out).
  730          */
  731         KDASSERT(icp->icp_running != 0);
  732         if (--icp->icp_running == 0 &&
  733             (icp->icp_flags & ICP_F_WAIT_FREEZE) != 0) {
  734                 icp->icp_flags &= ~ICP_F_WAIT_FREEZE;
  735                 wakeup(&icp->icp_qfreeze);
  736         }
  737 
  738         switch (icp->icp_status) {
  739         case ICP_S_BSY:
  740 #ifdef ICP_DEBUG
  741                 printf("%s: ICP_S_BSY received\n", icp->icp_dv.dv_xname);
  742 #endif
  743                 if (__predict_false((ic->ic_flags & IC_UCMD) != 0))
  744                         SIMPLEQ_INSERT_HEAD(&icp->icp_ucmd_queue, ic, ic_chain);
  745                 else
  746                         SIMPLEQ_INSERT_HEAD(&icp->icp_ccb_queue, ic, ic_chain);
  747                 break;
  748 
  749         default:
  750                 ic->ic_flags |= IC_COMPLETE;
  751 
  752                 if ((ic->ic_flags & IC_WAITING) != 0)
  753                         wakeup(ic);
  754                 else if (ic->ic_intr != NULL)
  755                         (*ic->ic_intr)(ic);
  756 
  757                 if (ICP_HAS_WORK(icp))
  758                         icp_ccb_enqueue(icp, NULL);
  759 
  760                 break;
  761         }
  762 
  763         return (1);
  764 }
  765 
  766 struct icp_ucmd_ctx {
  767         gdt_ucmd_t *iu_ucmd;
  768         u_int32_t iu_cnt;
  769 };
  770 
  771 void
  772 icp_ucmd_intr(struct icp_ccb *ic)
  773 {
  774         struct icp_softc *icp = (void *) ic->ic_dv;
  775         struct icp_ucmd_ctx *iu = ic->ic_context;
  776         gdt_ucmd_t *ucmd = iu->iu_ucmd;
  777 
  778         ucmd->status = icp->icp_status;
  779         ucmd->info = icp->icp_info;
  780 
  781         if (iu->iu_cnt != 0) {
  782                 bus_dmamap_sync(icp->icp_dmat,
  783                     icp->icp_scr_dmamap,
  784                     ICP_SCRATCH_UCMD, iu->iu_cnt,
  785                     BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
  786                 memcpy(ucmd->data,
  787                     icp->icp_scr + ICP_SCRATCH_UCMD, iu->iu_cnt);
  788         }
  789 
  790         icp->icp_ucmd_ccb = NULL;
  791 
  792         ic->ic_flags |= IC_COMPLETE;
  793         wakeup(ic);
  794 }
  795 
  796 /*
  797  * NOTE: We assume that it is safe to sleep here!
  798  */
  799 int
  800 icp_cmd(struct icp_softc *icp, u_int8_t service, u_int16_t opcode,
  801         u_int32_t arg1, u_int32_t arg2, u_int32_t arg3)
  802 {
  803         struct icp_ioctlcmd *icmd;
  804         struct icp_cachecmd *cc;
  805         struct icp_rawcmd *rc;
  806         int retries, rv;
  807         struct icp_ccb *ic;
  808 
  809         retries = ICP_RETRIES;
  810 
  811         do {
  812                 ic = icp_ccb_alloc_wait(icp);
  813                 memset(&ic->ic_cmd, 0, sizeof(ic->ic_cmd));
  814                 ic->ic_cmd.cmd_opcode = htole16(opcode);
  815 
  816                 switch (service) {
  817                 case ICP_CACHESERVICE:
  818                         if (opcode == ICP_IOCTL) {
  819                                 icmd = &ic->ic_cmd.cmd_packet.ic;
  820                                 icmd->ic_subfunc = htole16(arg1);
  821                                 icmd->ic_channel = htole32(arg2);
  822                                 icmd->ic_bufsize = htole32(arg3);
  823                                 icmd->ic_addr =
  824                                     htole32(icp->icp_scr_seg[0].ds_addr);
  825 
  826                                 bus_dmamap_sync(icp->icp_dmat,
  827                                     icp->icp_scr_dmamap, 0, arg3,
  828                                     BUS_DMASYNC_PREWRITE |
  829                                     BUS_DMASYNC_PREREAD);
  830                         } else {
  831                                 cc = &ic->ic_cmd.cmd_packet.cc;
  832                                 cc->cc_deviceno = htole16(arg1);
  833                                 cc->cc_blockno = htole32(arg2);
  834                         }
  835                         break;
  836 
  837                 case ICP_SCSIRAWSERVICE:
  838                         rc = &ic->ic_cmd.cmd_packet.rc;
  839                         rc->rc_direction = htole32(arg1);
  840                         rc->rc_bus = arg2;
  841                         rc->rc_target = arg3;
  842                         rc->rc_lun = arg3 >> 8;
  843                         break;
  844                 }
  845 
  846                 ic->ic_service = service;
  847                 ic->ic_cmdlen = sizeof(ic->ic_cmd);
  848                 rv = icp_ccb_poll(icp, ic, 10000);
  849 
  850                 switch (service) {
  851                 case ICP_CACHESERVICE:
  852                         if (opcode == ICP_IOCTL) {
  853                                 bus_dmamap_sync(icp->icp_dmat,
  854                                     icp->icp_scr_dmamap, 0, arg3,
  855                                     BUS_DMASYNC_POSTWRITE |
  856                                     BUS_DMASYNC_POSTREAD);
  857                         }
  858                         break;
  859                 }
  860 
  861                 icp_ccb_free(icp, ic);
  862         } while (rv != 0 && --retries > 0);
  863 
  864         return (icp->icp_status == ICP_S_OK);
  865 }
  866 
  867 int
  868 icp_ucmd(struct icp_softc *icp, gdt_ucmd_t *ucmd)
  869 {
  870         struct icp_ccb *ic;
  871         struct icp_ucmd_ctx iu;
  872         u_int32_t cnt;
  873         int error;
  874 
  875         if (ucmd->service == ICP_CACHESERVICE) {
  876                 if (ucmd->command.cmd_opcode == ICP_IOCTL) {
  877                         cnt = ucmd->command.cmd_packet.ic.ic_bufsize;
  878                         if (cnt > GDT_SCRATCH_SZ) {
  879                                 printf("%s: scratch buffer too small (%d/%d)\n",
  880                                     icp->icp_dv.dv_xname, GDT_SCRATCH_SZ, cnt);
  881                                 return (EINVAL);
  882                         }
  883                 } else {
  884                         cnt = ucmd->command.cmd_packet.cc.cc_blockcnt *
  885                             ICP_SECTOR_SIZE;
  886                         if (cnt > GDT_SCRATCH_SZ) {
  887                                 printf("%s: scratch buffer too small (%d/%d)\n",
  888                                     icp->icp_dv.dv_xname, GDT_SCRATCH_SZ, cnt);
  889                                 return (EINVAL);
  890                         }
  891                 }
  892         } else {
  893                 cnt = ucmd->command.cmd_packet.rc.rc_sdlen +
  894                     ucmd->command.cmd_packet.rc.rc_sense_len;
  895                 if (cnt > GDT_SCRATCH_SZ) {
  896                         printf("%s: scratch buffer too small (%d/%d)\n",
  897                             icp->icp_dv.dv_xname, GDT_SCRATCH_SZ, cnt);
  898                         return (EINVAL);
  899                 }
  900         }
  901 
  902         iu.iu_ucmd = ucmd;
  903         iu.iu_cnt = cnt;
  904 
  905         ic = icp_ccb_alloc_wait(icp);
  906         memset(&ic->ic_cmd, 0, sizeof(ic->ic_cmd));
  907         ic->ic_cmd.cmd_opcode = htole16(ucmd->command.cmd_opcode);
  908 
  909         if (ucmd->service == ICP_CACHESERVICE) {
  910                 if (ucmd->command.cmd_opcode == ICP_IOCTL) {
  911                         struct icp_ioctlcmd *icmd, *uicmd;
  912 
  913                         icmd = &ic->ic_cmd.cmd_packet.ic;
  914                         uicmd = &ucmd->command.cmd_packet.ic;
  915 
  916                         icmd->ic_subfunc = htole16(uicmd->ic_subfunc);
  917                         icmd->ic_channel = htole32(uicmd->ic_channel);
  918                         icmd->ic_bufsize = htole32(uicmd->ic_bufsize);
  919                         icmd->ic_addr =
  920                             htole32(icp->icp_scr_seg[0].ds_addr +
  921                                     ICP_SCRATCH_UCMD);
  922                 } else {
  923                         struct icp_cachecmd *cc, *ucc;
  924 
  925                         cc = &ic->ic_cmd.cmd_packet.cc;
  926                         ucc = &ucmd->command.cmd_packet.cc;
  927 
  928                         cc->cc_deviceno = htole16(ucc->cc_deviceno);
  929                         cc->cc_blockno = htole32(ucc->cc_blockno);
  930                         cc->cc_blockcnt = htole32(ucc->cc_blockcnt);
  931                         cc->cc_addr = htole32(0xffffffffU);
  932                         cc->cc_nsgent = htole32(1);
  933                         cc->cc_sg[0].sg_addr =
  934                             htole32(icp->icp_scr_seg[0].ds_addr +
  935                                     ICP_SCRATCH_UCMD);
  936                         cc->cc_sg[0].sg_len = htole32(cnt);
  937                 }
  938         } else {
  939                 struct icp_rawcmd *rc, *urc;
  940 
  941                 rc = &ic->ic_cmd.cmd_packet.rc;
  942                 urc = &ucmd->command.cmd_packet.rc;
  943 
  944                 rc->rc_direction = htole32(urc->rc_direction);
  945                 rc->rc_sdata = htole32(0xffffffffU);
  946                 rc->rc_sdlen = htole32(urc->rc_sdlen);
  947                 rc->rc_clen = htole32(urc->rc_clen);
  948                 memcpy(rc->rc_cdb, urc->rc_cdb, sizeof(rc->rc_cdb));
  949                 rc->rc_target = urc->rc_target;
  950                 rc->rc_lun = urc->rc_lun;
  951                 rc->rc_bus = urc->rc_bus;
  952                 rc->rc_sense_len = htole32(urc->rc_sense_len);
  953                 rc->rc_sense_addr =
  954                     htole32(icp->icp_scr_seg[0].ds_addr +
  955                             ICP_SCRATCH_UCMD + urc->rc_sdlen);
  956                 rc->rc_nsgent = htole32(1);
  957                 rc->rc_sg[0].sg_addr =
  958                     htole32(icp->icp_scr_seg[0].ds_addr + ICP_SCRATCH_UCMD);
  959                 rc->rc_sg[0].sg_len = htole32(cnt - urc->rc_sense_len);
  960         }
  961 
  962         ic->ic_service = ucmd->service;
  963         ic->ic_cmdlen = sizeof(ic->ic_cmd);
  964         ic->ic_context = &iu;
  965 
  966         /*
  967          * XXX What units are ucmd->timeout in?  Until we know, we
  968          * XXX just pull a number out of thin air.
  969          */
  970         if (__predict_false((error = icp_ccb_wait_user(icp, ic, 30000)) != 0))
  971                 printf("%s: error %d waiting for ucmd to complete\n",
  972                     icp->icp_dv.dv_xname, error);
  973 
  974         /* icp_ucmd_intr() has updated ucmd. */
  975         icp_ccb_free(icp, ic);
  976 
  977         return (error);
  978 }
  979 
  980 struct icp_ccb *
  981 icp_ccb_alloc(struct icp_softc *icp)
  982 {
  983         struct icp_ccb *ic;
  984         int s;
  985 
  986         s = splbio();
  987         if (__predict_false((ic =
  988                              SIMPLEQ_FIRST(&icp->icp_ccb_freelist)) == NULL)) {
  989                 splx(s);
  990                 return (NULL);
  991         }
  992         SIMPLEQ_REMOVE_HEAD(&icp->icp_ccb_freelist, ic_chain);
  993         splx(s);
  994 
  995         ic->ic_flags = IC_ALLOCED;
  996         return (ic);
  997 }
  998 
  999 struct icp_ccb *
 1000 icp_ccb_alloc_wait(struct icp_softc *icp)
 1001 {
 1002         struct icp_ccb *ic;
 1003         int s;
 1004 
 1005         s = splbio();
 1006         while ((ic = SIMPLEQ_FIRST(&icp->icp_ccb_freelist)) == NULL) {
 1007                 icp->icp_flags |= ICP_F_WAIT_CCB;
 1008                 (void) tsleep(&icp->icp_ccb_freelist, PRIBIO, "icpccb", 0);
 1009         }
 1010         SIMPLEQ_REMOVE_HEAD(&icp->icp_ccb_freelist, ic_chain);
 1011         splx(s);
 1012 
 1013         ic->ic_flags = IC_ALLOCED;
 1014         return (ic);
 1015 }
 1016 
 1017 void
 1018 icp_ccb_free(struct icp_softc *icp, struct icp_ccb *ic)
 1019 {
 1020         int s;
 1021 
 1022         s = splbio();
 1023         ic->ic_flags = 0;
 1024         ic->ic_intr = NULL;
 1025         SIMPLEQ_INSERT_HEAD(&icp->icp_ccb_freelist, ic, ic_chain);
 1026         if (__predict_false((icp->icp_flags & ICP_F_WAIT_CCB) != 0)) {
 1027                 icp->icp_flags &= ~ICP_F_WAIT_CCB;
 1028                 wakeup(&icp->icp_ccb_freelist);
 1029         }
 1030         splx(s);
 1031 }
 1032 
 1033 void
 1034 icp_ccb_enqueue(struct icp_softc *icp, struct icp_ccb *ic)
 1035 {
 1036         int s;
 1037 
 1038         s = splbio();
 1039 
 1040         if (ic != NULL) {
 1041                 if (__predict_false((ic->ic_flags & IC_UCMD) != 0))
 1042                         SIMPLEQ_INSERT_TAIL(&icp->icp_ucmd_queue, ic, ic_chain);
 1043                 else
 1044                         SIMPLEQ_INSERT_TAIL(&icp->icp_ccb_queue, ic, ic_chain);
 1045         }
 1046 
 1047         for (; icp->icp_qfreeze == 0;) {
 1048                 if (__predict_false((ic =
 1049                             SIMPLEQ_FIRST(&icp->icp_ucmd_queue)) != NULL)) {
 1050                         struct icp_ucmd_ctx *iu = ic->ic_context;
 1051                         gdt_ucmd_t *ucmd = iu->iu_ucmd;
 1052 
 1053                         /*
 1054                          * All user-generated commands share the same
 1055                          * scratch space, so if one is already running,
 1056                          * we have to stall the command queue.
 1057                          */
 1058                         if (icp->icp_ucmd_ccb != NULL)
 1059                                 break;
 1060                         if ((*icp->icp_test_busy)(icp))
 1061                                 break;
 1062                         icp->icp_ucmd_ccb = ic;
 1063 
 1064                         if (iu->iu_cnt != 0) {
 1065                                 memcpy(icp->icp_scr + ICP_SCRATCH_UCMD,
 1066                                     ucmd->data, iu->iu_cnt);
 1067                                 bus_dmamap_sync(icp->icp_dmat,
 1068                                     icp->icp_scr_dmamap,
 1069                                     ICP_SCRATCH_UCMD, iu->iu_cnt,
 1070                                     BUS_DMASYNC_PREREAD |
 1071                                     BUS_DMASYNC_PREWRITE);
 1072                         }
 1073                 } else if (__predict_true((ic =
 1074                                 SIMPLEQ_FIRST(&icp->icp_ccb_queue)) != NULL)) {
 1075                         if ((*icp->icp_test_busy)(icp))
 1076                                 break;
 1077                 } else {
 1078                         /* no command found */
 1079                         break;
 1080                 }
 1081                 icp_ccb_submit(icp, ic);
 1082                 if (__predict_false((ic->ic_flags & IC_UCMD) != 0))
 1083                         SIMPLEQ_REMOVE_HEAD(&icp->icp_ucmd_queue, ic_chain);
 1084                 else
 1085                         SIMPLEQ_REMOVE_HEAD(&icp->icp_ccb_queue, ic_chain);
 1086         }
 1087 
 1088         splx(s);
 1089 }
 1090 
 1091 int
 1092 icp_ccb_map(struct icp_softc *icp, struct icp_ccb *ic, void *data, int size,
 1093             int dir)
 1094 {
 1095         struct icp_sg *sg;
 1096         int nsegs, i, rv;
 1097         bus_dmamap_t xfer;
 1098 
 1099         xfer = ic->ic_xfer_map;
 1100 
 1101         rv = bus_dmamap_load(icp->icp_dmat, xfer, data, size, NULL,
 1102             BUS_DMA_NOWAIT | BUS_DMA_STREAMING |
 1103             ((dir & IC_XFER_IN) ? BUS_DMA_READ : BUS_DMA_WRITE));
 1104         if (rv != 0)
 1105                 return (rv);
 1106 
 1107         nsegs = xfer->dm_nsegs;
 1108         ic->ic_xfer_size = size;
 1109         ic->ic_nsgent = nsegs;
 1110         ic->ic_flags |= dir;
 1111         sg = ic->ic_sg;
 1112 
 1113         if (sg != NULL) {
 1114                 for (i = 0; i < nsegs; i++, sg++) {
 1115                         sg->sg_addr = htole32(xfer->dm_segs[i].ds_addr);
 1116                         sg->sg_len = htole32(xfer->dm_segs[i].ds_len);
 1117                 }
 1118         } else if (nsegs > 1)
 1119                 panic("icp_ccb_map: no SG list specified, but nsegs > 1");
 1120 
 1121         if ((dir & IC_XFER_OUT) != 0)
 1122                 i = BUS_DMASYNC_PREWRITE;
 1123         else /* if ((dir & IC_XFER_IN) != 0) */
 1124                 i = BUS_DMASYNC_PREREAD;
 1125 
 1126         bus_dmamap_sync(icp->icp_dmat, xfer, 0, ic->ic_xfer_size, i);
 1127         return (0);
 1128 }
 1129 
 1130 void
 1131 icp_ccb_unmap(struct icp_softc *icp, struct icp_ccb *ic)
 1132 {
 1133         int i;
 1134 
 1135         if ((ic->ic_flags & IC_XFER_OUT) != 0)
 1136                 i = BUS_DMASYNC_POSTWRITE;
 1137         else /* if ((ic->ic_flags & IC_XFER_IN) != 0) */
 1138                 i = BUS_DMASYNC_POSTREAD;
 1139 
 1140         bus_dmamap_sync(icp->icp_dmat, ic->ic_xfer_map, 0, ic->ic_xfer_size, i);
 1141         bus_dmamap_unload(icp->icp_dmat, ic->ic_xfer_map);
 1142 }
 1143 
 1144 int
 1145 icp_ccb_poll(struct icp_softc *icp, struct icp_ccb *ic, int timo)
 1146 {
 1147         int s, rv;
 1148 
 1149         s = splbio();
 1150 
 1151         for (timo = ICP_BUSY_WAIT_MS * 100; timo != 0; timo--) {
 1152                 if (!(*icp->icp_test_busy)(icp))
 1153                         break;
 1154                 DELAY(10);
 1155         }
 1156         if (timo == 0) {
 1157                 printf("%s: submit: busy\n", icp->icp_dv.dv_xname);
 1158                 return (EAGAIN);
 1159         }
 1160 
 1161         icp_ccb_submit(icp, ic);
 1162 
 1163         if (cold) {
 1164                 for (timo *= 10; timo != 0; timo--) {
 1165                         DELAY(100);
 1166                         icp_intr(icp);
 1167                         if ((ic->ic_flags & IC_COMPLETE) != 0)
 1168                                 break;
 1169                 }
 1170         } else {
 1171                 ic->ic_flags |= IC_WAITING;
 1172                 while ((ic->ic_flags & IC_COMPLETE) == 0) {
 1173                         if ((rv = tsleep(ic, PRIBIO, "icpwccb",
 1174                                          mstohz(timo))) != 0) {
 1175                                 timo = 0;
 1176                                 break;
 1177                         }
 1178                 }
 1179         }
 1180 
 1181         if (timo != 0) {
 1182                 if (ic->ic_status != ICP_S_OK) {
 1183 #ifdef ICP_DEBUG
 1184                         printf("%s: request failed; status=0x%04x\n",
 1185                             icp->icp_dv.dv_xname, ic->ic_status);
 1186 #endif
 1187                         rv = EIO;
 1188                 } else
 1189                         rv = 0;
 1190         } else {
 1191                 printf("%s: command timed out\n", icp->icp_dv.dv_xname);
 1192                 rv = EIO;
 1193         }
 1194 
 1195         while ((*icp->icp_test_busy)(icp) != 0)
 1196                 DELAY(10);
 1197 
 1198         splx(s);
 1199 
 1200         return (rv);
 1201 }
 1202 
 1203 int
 1204 icp_ccb_wait(struct icp_softc *icp, struct icp_ccb *ic, int timo)
 1205 {
 1206         int s, rv;
 1207 
 1208         ic->ic_flags |= IC_WAITING;
 1209 
 1210         s = splbio();
 1211         icp_ccb_enqueue(icp, ic);
 1212         while ((ic->ic_flags & IC_COMPLETE) == 0) {
 1213                 if ((rv = tsleep(ic, PRIBIO, "icpwccb", mstohz(timo))) != 0) {
 1214                         splx(s);
 1215                         return (rv);
 1216                 }
 1217         }
 1218         splx(s);
 1219 
 1220         if (ic->ic_status != ICP_S_OK) {
 1221                 printf("%s: command failed; status=%x\n", icp->icp_dv.dv_xname,
 1222                     ic->ic_status);
 1223                 return (EIO);
 1224         }
 1225 
 1226         return (0);
 1227 }
 1228 
 1229 int
 1230 icp_ccb_wait_user(struct icp_softc *icp, struct icp_ccb *ic, int timo)
 1231 {
 1232         int s, rv;
 1233 
 1234         ic->ic_dv = &icp->icp_dv;
 1235         ic->ic_intr = icp_ucmd_intr;
 1236         ic->ic_flags |= IC_UCMD;
 1237 
 1238         s = splbio();
 1239         icp_ccb_enqueue(icp, ic);
 1240         while ((ic->ic_flags & IC_COMPLETE) == 0) {
 1241                 if ((rv = tsleep(ic, PRIBIO, "icpwuccb", mstohz(timo))) != 0) {
 1242                         splx(s);
 1243                         return (rv);
 1244                 }
 1245         }
 1246         splx(s);
 1247 
 1248         return (0);
 1249 }
 1250 
 1251 void
 1252 icp_ccb_submit(struct icp_softc *icp, struct icp_ccb *ic)
 1253 {
 1254 
 1255         ic->ic_cmdlen = (ic->ic_cmdlen + 3) & ~3;
 1256 
 1257         (*icp->icp_set_sema0)(icp);
 1258         DELAY(10);
 1259 
 1260         ic->ic_cmd.cmd_boardnode = htole32(ICP_LOCALBOARD);
 1261         ic->ic_cmd.cmd_cmdindex = htole32(ic->ic_ident);
 1262 
 1263         icp->icp_running++;
 1264 
 1265         (*icp->icp_copy_cmd)(icp, ic);
 1266         (*icp->icp_release_event)(icp, ic);
 1267 }
 1268 
 1269 int
 1270 icp_freeze(struct icp_softc *icp)
 1271 {
 1272         int s, error = 0;
 1273 
 1274         s = splbio();
 1275         if (icp->icp_qfreeze++ == 0) {
 1276                 while (icp->icp_running != 0) {
 1277                         icp->icp_flags |= ICP_F_WAIT_FREEZE;
 1278                         error = tsleep(&icp->icp_qfreeze, PRIBIO|PCATCH,
 1279                             "icpqfrz", 0);
 1280                         if (error != 0 && --icp->icp_qfreeze == 0 &&
 1281                             ICP_HAS_WORK(icp)) {
 1282                                 icp_ccb_enqueue(icp, NULL);
 1283                                 break;
 1284                         }
 1285                 }
 1286         }
 1287         splx(s);
 1288 
 1289         return (error);
 1290 }
 1291 
 1292 void
 1293 icp_unfreeze(struct icp_softc *icp)
 1294 {
 1295         int s;
 1296 
 1297         s = splbio();
 1298         KDASSERT(icp->icp_qfreeze != 0);
 1299         if (--icp->icp_qfreeze == 0 && ICP_HAS_WORK(icp))
 1300                 icp_ccb_enqueue(icp, NULL);
 1301         splx(s);
 1302 }
 1303 
 1304 /* XXX Global - should be per-controller? XXX */
 1305 static gdt_evt_str icp_event_buffer[ICP_MAX_EVENTS];
 1306 static int icp_event_oldidx;
 1307 static int icp_event_lastidx;
 1308 
 1309 gdt_evt_str *
 1310 icp_store_event(struct icp_softc *icp, u_int16_t source, u_int16_t idx,
 1311     gdt_evt_data *evt)
 1312 {
 1313         gdt_evt_str *e;
 1314 
 1315         /* no source == no event */
 1316         if (source == 0)
 1317                 return (NULL);
 1318 
 1319         e = &icp_event_buffer[icp_event_lastidx];
 1320         if (e->event_source == source && e->event_idx == idx &&
 1321             ((evt->size != 0 && e->event_data.size != 0 &&
 1322               memcmp(&e->event_data.eu, &evt->eu, evt->size) == 0) ||
 1323              (evt->size == 0 && e->event_data.size == 0 &&
 1324               strcmp((char *) e->event_data.event_string,
 1325                      (char *) evt->event_string) == 0))) {
 1326                 e->last_stamp = time.tv_sec;
 1327                 e->same_count++;
 1328         } else {
 1329                 if (icp_event_buffer[icp_event_lastidx].event_source != 0) {
 1330                         icp_event_lastidx++;
 1331                         if (icp_event_lastidx == ICP_MAX_EVENTS)
 1332                                 icp_event_lastidx = 0;
 1333                         if (icp_event_lastidx == icp_event_oldidx) {
 1334                                 icp_event_oldidx++;
 1335                                 if (icp_event_oldidx == ICP_MAX_EVENTS)
 1336                                         icp_event_oldidx = 0;
 1337                         }
 1338                 }
 1339                 e = &icp_event_buffer[icp_event_lastidx];
 1340                 e->event_source = source;
 1341                 e->event_idx = idx;
 1342                 e->first_stamp = e->last_stamp = time.tv_sec;
 1343                 e->same_count = 1;
 1344                 e->event_data = *evt;
 1345                 e->application = 0;
 1346         }
 1347         return (e);
 1348 }
 1349 
 1350 int
 1351 icp_read_event(struct icp_softc *icp, int handle, gdt_evt_str *estr)
 1352 {
 1353         gdt_evt_str *e;
 1354         int eindex, s;
 1355 
 1356         s = splbio();
 1357 
 1358         if (handle == -1)
 1359                 eindex = icp_event_oldidx;
 1360         else
 1361                 eindex = handle;
 1362 
 1363         estr->event_source = 0;
 1364 
 1365         if (eindex < 0 || eindex >= ICP_MAX_EVENTS) {
 1366                 splx(s);
 1367                 return (eindex);
 1368         }
 1369 
 1370         e = &icp_event_buffer[eindex];
 1371         if (e->event_source != 0) {
 1372                 if (eindex != icp_event_lastidx) {
 1373                         eindex++;
 1374                         if (eindex == ICP_MAX_EVENTS)
 1375                                 eindex = 0;
 1376                 } else
 1377                         eindex = -1;
 1378                 memcpy(estr, e, sizeof(gdt_evt_str));
 1379         }
 1380 
 1381         splx(s);
 1382 
 1383         return (eindex);
 1384 }
 1385 
 1386 void
 1387 icp_readapp_event(struct icp_softc *icp, u_int8_t application,
 1388     gdt_evt_str *estr)
 1389 {
 1390         gdt_evt_str *e;
 1391         int found = 0, eindex, s;
 1392 
 1393         s = splbio();
 1394 
 1395         eindex = icp_event_oldidx;
 1396         for (;;) {
 1397                 e = &icp_event_buffer[eindex];
 1398                 if (e->event_source == 0)
 1399                         break;
 1400                 if ((e->application & application) == 0) {
 1401                         e->application |= application;
 1402                         found = 1;
 1403                         break;
 1404                 }
 1405                 if (eindex == icp_event_lastidx)
 1406                         break;
 1407                 eindex++;
 1408                 if (eindex == ICP_MAX_EVENTS)
 1409                         eindex = 0;
 1410         }
 1411         if (found)
 1412                 memcpy(estr, e, sizeof(gdt_evt_str));
 1413         else
 1414                 estr->event_source = 0;
 1415 
 1416         splx(s);
 1417 }
 1418 
 1419 void
 1420 icp_clear_events(struct icp_softc *icp)
 1421 {
 1422         int s;
 1423 
 1424         s = splbio();
 1425         icp_event_oldidx = icp_event_lastidx = 0;
 1426         memset(icp_event_buffer, 0, sizeof(icp_event_buffer));
 1427         splx(s);
 1428 }

Cache object: 0c9ec7e9a704c9f48945f1df53e0a569


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