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

Cache object: cb30985aae5bd89404c4f9afc18f1dfa


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