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/ld_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: ld_icp.c,v 1.32 2020/08/14 09:28:29 chs Exp $  */
    2 
    3 /*-
    4  * Copyright (c) 2002 The NetBSD Foundation, Inc.
    5  * All rights reserved.
    6  *
    7  * This code is derived from software contributed to The NetBSD Foundation
    8  * by Andrew Doran.
    9  *
   10  * Redistribution and use in source and binary forms, with or without
   11  * modification, are permitted provided that the following conditions
   12  * are met:
   13  * 1. Redistributions of source code must retain the above copyright
   14  *    notice, this list of conditions and the following disclaimer.
   15  * 2. Redistributions in binary form must reproduce the above copyright
   16  *    notice, this list of conditions and the following disclaimer in the
   17  *    documentation and/or other materials provided with the distribution.
   18  *
   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  * ICP-Vortex "GDT" front-end for ld(4) driver.
   34  */
   35 
   36 #include <sys/cdefs.h>
   37 __KERNEL_RCSID(0, "$NetBSD: ld_icp.c,v 1.32 2020/08/14 09:28:29 chs Exp $");
   38 
   39 #include <sys/param.h>
   40 #include <sys/systm.h>
   41 #include <sys/kernel.h>
   42 #include <sys/device.h>
   43 #include <sys/buf.h>
   44 #include <sys/bufq.h>
   45 #include <sys/endian.h>
   46 #include <sys/dkio.h>
   47 #include <sys/disk.h>
   48 #include <sys/module.h>
   49 #include <sys/bus.h>
   50 
   51 #include <dev/ldvar.h>
   52 
   53 #include <dev/ic/icpreg.h>
   54 #include <dev/ic/icpvar.h>
   55 
   56 #include "ioconf.h"
   57 
   58 struct ld_icp_softc {
   59         struct  ld_softc sc_ld;
   60         int     sc_hwunit;
   61 };
   62 
   63 static void     ld_icp_attach(device_t, device_t, void *);
   64 static int      ld_icp_detach(device_t, int);
   65 static int      ld_icp_dobio(struct ld_icp_softc *, void *, int, int, int,
   66                      struct buf *);
   67 static int      ld_icp_dump(struct ld_softc *, void *, int, int);
   68 static int      ld_icp_flush(struct ld_softc *, bool);
   69 static int      ld_icp_ioctl(struct ld_softc *, u_long, void *, int32_t, bool);
   70 static void     ld_icp_intr(struct icp_ccb *);
   71 static int      ld_icp_match(device_t, cfdata_t, void *);
   72 static int      ld_icp_start(struct ld_softc *, struct buf *);
   73 
   74 static void     ld_icp_adjqparam(device_t, int);
   75 
   76 CFATTACH_DECL_NEW(ld_icp, sizeof(struct ld_icp_softc),
   77     ld_icp_match, ld_icp_attach, ld_icp_detach, NULL);
   78 
   79 static const struct icp_servicecb ld_icp_servicecb = {
   80         ld_icp_adjqparam,
   81 };
   82 
   83 static int
   84 ld_icp_match(device_t parent, cfdata_t match, void *aux)
   85 {
   86         struct icp_attach_args *icpa;
   87 
   88         icpa = aux;
   89 
   90         return (icpa->icpa_unit < ICPA_UNIT_SCSI);
   91 }
   92 
   93 static void
   94 ld_icp_attach(device_t parent, device_t self, void *aux)
   95 {
   96         struct icp_attach_args *icpa = aux;
   97         struct ld_icp_softc *sc = device_private(self);
   98         struct ld_softc *ld = &sc->sc_ld;
   99         struct icp_softc *icp = device_private(parent);
  100         struct icp_cachedrv *cd = &icp->icp_cdr[icpa->icpa_unit];
  101         struct icp_cdevinfo *cdi;
  102         const char *str;
  103         int t;
  104 
  105         ld->sc_dv = self;
  106 
  107         icp_register_servicecb(icp, icpa->icpa_unit, &ld_icp_servicecb);
  108 
  109         sc->sc_hwunit = icpa->icpa_unit;
  110         ld->sc_maxxfer = ICP_MAX_XFER;
  111         ld->sc_secsize = ICP_SECTOR_SIZE;
  112         ld->sc_start = ld_icp_start;
  113         ld->sc_dump = ld_icp_dump;
  114         ld->sc_ioctl = ld_icp_ioctl;
  115         ld->sc_secperunit = cd->cd_size;
  116         ld->sc_flags = LDF_ENABLED;
  117         ld->sc_maxqueuecnt = icp->icp_openings;
  118 
  119         if (!icp_cmd(icp, ICP_CACHESERVICE, ICP_IOCTL, ICP_CACHE_DRV_INFO,
  120             sc->sc_hwunit, sizeof(struct icp_cdevinfo))) {
  121                 aprint_error(": unable to retrieve device info\n");
  122                 ld->sc_flags = LDF_ENABLED;
  123                 goto out;
  124         }
  125         cdi = (struct icp_cdevinfo *)icp->icp_scr;
  126 
  127         aprint_normal(": <%.8s>, ", cdi->ld_name);
  128         t = le32toh(cdi->ld_dtype) >> 16;
  129 
  130         /*
  131          * Print device type.
  132          */
  133         if (le32toh(cdi->ld_dcnt) > 1 || le32toh(cdi->ld_slave) != -1)
  134                 str = "RAID-1";
  135         else if (t == 0)
  136                 str = "JBOD";
  137         else if (t == 1)
  138                 str = "RAID-0";
  139         else if (t == 2)
  140                 str = "Chain";
  141         else
  142                 str = "unknown type";
  143 
  144         aprint_normal("type: %s, ", str);
  145 
  146         /*
  147          * Print device status.
  148          */
  149         if (t > 2)
  150                 str = "missing";
  151         else if ((cdi->ld_error & 1) != 0) {
  152                 str = "fault";
  153                 ld->sc_flags = LDF_ENABLED;
  154         } else if ((cdi->ld_error & 2) != 0)
  155                 str = "invalid";
  156         else {
  157                 str = "optimal";
  158                 ld->sc_flags = LDF_ENABLED;
  159         }
  160 
  161         aprint_normal("status: %s\n", str);
  162 
  163  out:
  164         ldattach(ld, BUFQ_DISK_DEFAULT_STRAT);
  165 }
  166 
  167 static int
  168 ld_icp_detach(device_t dv, int flags)
  169 {
  170         struct ld_softc *ldsc = device_private(dv);
  171         int rv;
  172 
  173         if ((rv = ldbegindetach(ldsc, flags)) != 0)
  174                 return (rv);
  175         ldenddetach(ldsc);
  176 
  177         return (0);
  178 }
  179 
  180 static int
  181 ld_icp_dobio(struct ld_icp_softc *sc, void *data, int datasize, int blkno,
  182              int dowrite, struct buf *bp)
  183 {
  184         struct icp_cachecmd *cc;
  185         struct icp_ccb *ic;
  186         struct icp_softc *icp;
  187         int s, rv;
  188 
  189         icp = device_private(device_parent(sc->sc_ld.sc_dv));
  190 
  191         /*
  192          * Allocate a command control block.
  193          */
  194         if (__predict_false((ic = icp_ccb_alloc(icp)) == NULL))
  195                 return (EAGAIN);
  196 
  197         /*
  198          * Map the data transfer.
  199          */
  200         cc = &ic->ic_cmd.cmd_packet.cc;
  201         ic->ic_sg = cc->cc_sg;
  202         ic->ic_service = ICP_CACHESERVICE;
  203 
  204         rv = icp_ccb_map(icp, ic, data, datasize,
  205             dowrite ? IC_XFER_OUT : IC_XFER_IN);
  206         if (rv != 0) {
  207                 icp_ccb_free(icp, ic);
  208                 return (rv);
  209         }
  210 
  211         /*
  212          * Build the command.
  213          */
  214         ic->ic_cmd.cmd_opcode = htole16((dowrite ? ICP_WRITE : ICP_READ));
  215         cc->cc_deviceno = htole16(sc->sc_hwunit);
  216         cc->cc_blockno = htole32(blkno);
  217         cc->cc_blockcnt = htole32(datasize / ICP_SECTOR_SIZE);
  218         cc->cc_addr = ~0;       /* scatter gather */
  219         cc->cc_nsgent = htole32(ic->ic_nsgent);
  220 
  221         ic->ic_cmdlen = (u_long)ic->ic_sg - (u_long)&ic->ic_cmd +
  222             ic->ic_nsgent * sizeof(*ic->ic_sg);
  223 
  224         /*
  225          * Fire it off to the controller.
  226          */
  227         if (bp == NULL) {
  228                 s = splbio();
  229                 rv = icp_ccb_poll(icp, ic, 10000);
  230                 icp_ccb_unmap(icp, ic);
  231                 icp_ccb_free(icp, ic);
  232                 splx(s);
  233         } else {
  234                 ic->ic_intr = ld_icp_intr;
  235                 ic->ic_context = bp;
  236                 ic->ic_dv = sc->sc_ld.sc_dv;
  237                 icp_ccb_enqueue(icp, ic);
  238         }
  239 
  240         return (rv);
  241 }
  242 
  243 static int
  244 ld_icp_start(struct ld_softc *ld, struct buf *bp)
  245 {
  246 
  247         return (ld_icp_dobio((struct ld_icp_softc *)ld, bp->b_data,
  248             bp->b_bcount, bp->b_rawblkno, (bp->b_flags & B_READ) == 0, bp));
  249 }
  250 
  251 static int
  252 ld_icp_dump(struct ld_softc *ld, void *data, int blkno, int blkcnt)
  253 {
  254 
  255         return (ld_icp_dobio((struct ld_icp_softc *)ld, data,
  256             blkcnt * ld->sc_secsize, blkno, 1, NULL));
  257 }
  258 
  259 /* ARGSUSED */
  260 static int
  261 ld_icp_flush(struct ld_softc *ld, bool poll)
  262 {
  263         struct ld_icp_softc *sc;
  264         struct icp_softc *icp;
  265         struct icp_cachecmd *cc;
  266         struct icp_ccb *ic;
  267         int rv;
  268 
  269         sc = (struct ld_icp_softc *)ld;
  270         icp = device_private(device_parent(ld->sc_dv));
  271 
  272         ic = icp_ccb_alloc_wait(icp);
  273         ic->ic_cmd.cmd_opcode = htole16(ICP_FLUSH);
  274 
  275         cc = &ic->ic_cmd.cmd_packet.cc;
  276         cc->cc_deviceno = htole16(sc->sc_hwunit);
  277         cc->cc_blockno = htole32(1);
  278         cc->cc_blockcnt = 0;
  279         cc->cc_addr = 0;
  280         cc->cc_nsgent = 0;
  281 
  282         ic->ic_cmdlen = (u_long)&cc->cc_sg - (u_long)&ic->ic_cmd;
  283         ic->ic_service = ICP_CACHESERVICE;
  284 
  285         rv = icp_ccb_wait(icp, ic, 30000);
  286         icp_ccb_free(icp, ic);
  287 
  288         return (rv);
  289 }
  290 
  291 static int
  292 ld_icp_ioctl(struct ld_softc *ld, u_long cmd, void *addr, int32_t flag, bool poll)
  293 {
  294         int error;
  295 
  296         switch (cmd) {
  297         case DIOCCACHESYNC:
  298                 error = ld_icp_flush(ld, poll);
  299                 break;
  300 
  301         default:
  302                 error = EPASSTHROUGH;
  303                 break;
  304         }
  305 
  306         return error;
  307 }
  308 
  309 static void
  310 ld_icp_intr(struct icp_ccb *ic)
  311 {
  312         struct buf *bp;
  313         struct ld_icp_softc *sc;
  314         struct icp_softc *icp;
  315 
  316         bp = ic->ic_context;
  317         sc = device_private(ic->ic_dv);
  318         icp = device_private(device_parent(sc->sc_ld.sc_dv));
  319 
  320         if (ic->ic_status != ICP_S_OK) {
  321                 aprint_error_dev(ic->ic_dv, "request failed; status=0x%04x\n",
  322                     ic->ic_status);
  323                 bp->b_error = EIO;
  324                 bp->b_resid = bp->b_bcount;
  325 
  326                 icp->icp_evt.size = sizeof(icp->icp_evt.eu.sync);
  327                 icp->icp_evt.eu.sync.ionode = device_unit(icp->icp_dv);
  328                 icp->icp_evt.eu.sync.service = icp->icp_service;
  329                 icp->icp_evt.eu.sync.status = icp->icp_status;
  330                 icp->icp_evt.eu.sync.info = icp->icp_info;
  331                 icp->icp_evt.eu.sync.hostdrive = sc->sc_hwunit;
  332                 if (icp->icp_status >= 0x8000)
  333                         icp_store_event(icp, GDT_ES_SYNC, 0, &icp->icp_evt);
  334                 else
  335                         icp_store_event(icp, GDT_ES_SYNC, icp->icp_service,
  336                             &icp->icp_evt);
  337         } else
  338                 bp->b_resid = 0;
  339 
  340         icp_ccb_unmap(icp, ic);
  341         icp_ccb_free(icp, ic);
  342         lddone(&sc->sc_ld, bp);
  343 }
  344 
  345 static void
  346 ld_icp_adjqparam(device_t dv, int openings)
  347 {
  348 
  349         ldadjqparam(device_private(dv), openings);
  350 }
  351 
  352 MODULE(MODULE_CLASS_DRIVER, ld_icp, "ld");      /* no icp module yet */
  353 
  354 #ifdef _MODULE
  355 /*
  356  * XXX Don't allow ioconf.c to redefine the "struct cfdriver ld_cd"
  357  * XXX it will be defined in the common-code module
  358  */     
  359 #undef  CFDRIVER_DECL
  360 #define CFDRIVER_DECL(name, class, attr)
  361 #include "ioconf.c"
  362 #endif
  363         
  364 static int
  365 ld_icp_modcmd(modcmd_t cmd, void *opaque)
  366 {       
  367 #ifdef _MODULE
  368         /*
  369          * We ignore the cfdriver_vec[] that ioconf provides, since
  370          * the cfdrivers are attached already.
  371          */
  372         static struct cfdriver * const no_cfdriver_vec[] = { NULL };
  373 #endif
  374         int error = 0;
  375         
  376 #ifdef _MODULE 
  377         switch (cmd) {
  378         case MODULE_CMD_INIT:
  379                 error = config_init_component(no_cfdriver_vec,
  380                     cfattach_ioconf_ld_icp, cfdata_ioconf_ld_icp);
  381                 break;
  382         case MODULE_CMD_FINI:
  383                 error = config_fini_component(no_cfdriver_vec,
  384                     cfattach_ioconf_ld_icp, cfdata_ioconf_ld_icp);
  385                 break;
  386         default:
  387                 error = ENOTTY;
  388                 break;
  389         }
  390 #endif
  391 
  392         return error;
  393 }

Cache object: da7dc0799f819c867e09faa7998750c3


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