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/cac.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: cac.c,v 1.47 2008/06/08 12:43:51 tsutsui Exp $ */
    2 
    3 /*-
    4  * Copyright (c) 2000, 2006, 2007 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  * Driver for Compaq array controllers.
   34  */
   35 
   36 #include <sys/cdefs.h>
   37 __KERNEL_RCSID(0, "$NetBSD: cac.c,v 1.47 2008/06/08 12:43:51 tsutsui Exp $");
   38 
   39 #include "bio.h"
   40 
   41 #include <sys/param.h>
   42 #include <sys/systm.h>
   43 #include <sys/kernel.h>
   44 #include <sys/device.h>
   45 #include <sys/queue.h>
   46 #include <sys/proc.h>
   47 #include <sys/buf.h>
   48 #include <sys/endian.h>
   49 #include <sys/malloc.h>
   50 #include <sys/pool.h>
   51 
   52 #include <uvm/uvm_extern.h>
   53 
   54 #include <sys/bswap.h>
   55 #include <sys/bus.h>
   56 
   57 #include <dev/ic/cacreg.h>
   58 #include <dev/ic/cacvar.h>
   59 
   60 #if NBIO > 0
   61 #include <dev/biovar.h>
   62 #endif /* NBIO > 0 */
   63 
   64 #include "locators.h"
   65 
   66 static struct   cac_ccb *cac_ccb_alloc(struct cac_softc *, int);
   67 static void     cac_ccb_done(struct cac_softc *, struct cac_ccb *);
   68 static void     cac_ccb_free(struct cac_softc *, struct cac_ccb *);
   69 static int      cac_ccb_poll(struct cac_softc *, struct cac_ccb *, int);
   70 static int      cac_ccb_start(struct cac_softc *, struct cac_ccb *);
   71 static int      cac_print(void *, const char *);
   72 static void     cac_shutdown(void *);
   73 
   74 static struct   cac_ccb *cac_l0_completed(struct cac_softc *);
   75 static int      cac_l0_fifo_full(struct cac_softc *);
   76 static void     cac_l0_intr_enable(struct cac_softc *, int);
   77 static int      cac_l0_intr_pending(struct cac_softc *);
   78 static void     cac_l0_submit(struct cac_softc *, struct cac_ccb *);
   79 
   80 static void     *cac_sdh;       /* shutdown hook */
   81 
   82 #if NBIO > 0
   83 int             cac_ioctl(struct device *, u_long, void *);
   84 int             cac_ioctl_vol(struct cac_softc *, struct bioc_vol *);
   85 int             cac_create_sensors(struct cac_softc *);
   86 void            cac_sensor_refresh(struct sysmon_envsys *, envsys_data_t *);
   87 #endif /* NBIO > 0 */
   88 
   89 const struct cac_linkage cac_l0 = {
   90         cac_l0_completed,
   91         cac_l0_fifo_full,
   92         cac_l0_intr_enable,
   93         cac_l0_intr_pending,
   94         cac_l0_submit
   95 };
   96 
   97 /*
   98  * Initialise our interface to the controller.
   99  */
  100 int
  101 cac_init(struct cac_softc *sc, const char *intrstr, int startfw)
  102 {
  103         struct cac_controller_info cinfo;
  104         struct cac_attach_args caca;
  105         int error, rseg, size, i;
  106         bus_dma_segment_t seg;
  107         struct cac_ccb *ccb;
  108         int locs[CACCF_NLOCS];
  109         char firm[8];
  110 
  111         if (intrstr != NULL)
  112                 aprint_normal_dev(&sc->sc_dv, "interrupting at %s\n",
  113                     intrstr);
  114 
  115         SIMPLEQ_INIT(&sc->sc_ccb_free);
  116         SIMPLEQ_INIT(&sc->sc_ccb_queue);
  117         mutex_init(&sc->sc_mutex, MUTEX_DEFAULT, IPL_VM);
  118         cv_init(&sc->sc_ccb_cv, "cacccb");
  119 
  120         size = sizeof(struct cac_ccb) * CAC_MAX_CCBS;
  121 
  122         if ((error = bus_dmamem_alloc(sc->sc_dmat, size, PAGE_SIZE, 0, &seg, 1,
  123             &rseg, BUS_DMA_NOWAIT)) != 0) {
  124                 aprint_error_dev(&sc->sc_dv, "unable to allocate CCBs, error = %d\n",
  125                     error);
  126                 return (-1);
  127         }
  128 
  129         if ((error = bus_dmamem_map(sc->sc_dmat, &seg, rseg, size,
  130             (void **)&sc->sc_ccbs,
  131             BUS_DMA_NOWAIT | BUS_DMA_COHERENT)) != 0) {
  132                 aprint_error_dev(&sc->sc_dv, "unable to map CCBs, error = %d\n",
  133                     error);
  134                 return (-1);
  135         }
  136 
  137         if ((error = bus_dmamap_create(sc->sc_dmat, size, 1, size, 0,
  138             BUS_DMA_NOWAIT, &sc->sc_dmamap)) != 0) {
  139                 aprint_error_dev(&sc->sc_dv, "unable to create CCB DMA map, error = %d\n",
  140                     error);
  141                 return (-1);
  142         }
  143 
  144         if ((error = bus_dmamap_load(sc->sc_dmat, sc->sc_dmamap, sc->sc_ccbs,
  145             size, NULL, BUS_DMA_NOWAIT)) != 0) {
  146                 aprint_error_dev(&sc->sc_dv, "unable to load CCB DMA map, error = %d\n",
  147                     error);
  148                 return (-1);
  149         }
  150 
  151         sc->sc_ccbs_paddr = sc->sc_dmamap->dm_segs[0].ds_addr;
  152         memset(sc->sc_ccbs, 0, size);
  153         ccb = (struct cac_ccb *)sc->sc_ccbs;
  154 
  155         for (i = 0; i < CAC_MAX_CCBS; i++, ccb++) {
  156                 /* Create the DMA map for this CCB's data */
  157                 error = bus_dmamap_create(sc->sc_dmat, CAC_MAX_XFER,
  158                     CAC_SG_SIZE, CAC_MAX_XFER, 0,
  159                     BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW,
  160                     &ccb->ccb_dmamap_xfer);
  161 
  162                 if (error) {
  163                         aprint_error_dev(&sc->sc_dv, "can't create ccb dmamap (%d)\n",
  164                             error);
  165                         break;
  166                 }
  167 
  168                 ccb->ccb_flags = 0;
  169                 ccb->ccb_paddr = sc->sc_ccbs_paddr + i * sizeof(struct cac_ccb);
  170                 SIMPLEQ_INSERT_TAIL(&sc->sc_ccb_free, ccb, ccb_chain);
  171         }
  172 
  173         /* Start firmware background tasks, if needed. */
  174         if (startfw) {
  175                 if (cac_cmd(sc, CAC_CMD_START_FIRMWARE, &cinfo, sizeof(cinfo),
  176                     0, 0, CAC_CCB_DATA_IN, NULL)) {
  177                         aprint_error_dev(&sc->sc_dv, "CAC_CMD_START_FIRMWARE failed\n");
  178                         return (-1);
  179                 }
  180         }
  181 
  182         if (cac_cmd(sc, CAC_CMD_GET_CTRL_INFO, &cinfo, sizeof(cinfo), 0, 0,
  183             CAC_CCB_DATA_IN, NULL)) {
  184                 aprint_error_dev(&sc->sc_dv, "CAC_CMD_GET_CTRL_INFO failed\n");
  185                 return (-1);
  186         }
  187 
  188         strlcpy(firm, cinfo.firm_rev, 4+1);
  189         printf("%s: %d channels, firmware <%s>\n", device_xname(&sc->sc_dv),
  190             cinfo.scsi_chips, firm);
  191 
  192         sc->sc_nunits = cinfo.num_drvs;
  193         for (i = 0; i < cinfo.num_drvs; i++) {
  194                 caca.caca_unit = i;
  195 
  196                 locs[CACCF_UNIT] = i;
  197 
  198                 config_found_sm_loc(&sc->sc_dv, "cac", locs, &caca,
  199                     cac_print, config_stdsubmatch);
  200         }
  201 
  202         /* Set our `shutdownhook' before we start any device activity. */
  203         if (cac_sdh == NULL)
  204                 cac_sdh = shutdownhook_establish(cac_shutdown, NULL);
  205 
  206         mutex_enter(&sc->sc_mutex);
  207         (*sc->sc_cl.cl_intr_enable)(sc, CAC_INTR_ENABLE);
  208         mutex_exit(&sc->sc_mutex);
  209 
  210 #if NBIO > 0
  211         if (bio_register(&sc->sc_dv, cac_ioctl) != 0)
  212                 aprint_error_dev(&sc->sc_dv, "controller registration failed");
  213         else
  214                 sc->sc_ioctl = cac_ioctl;
  215         if (cac_create_sensors(sc) != 0)
  216                 aprint_error_dev(&sc->sc_dv, "unable to create sensors\n");
  217 #endif
  218 
  219         return (0);
  220 }
  221 
  222 /*
  223  * Shut down all `cac' controllers.
  224  */
  225 static void
  226 cac_shutdown(void *cookie)
  227 {
  228         extern struct cfdriver cac_cd;
  229         struct cac_softc *sc;
  230         u_int8_t tbuf[512];
  231         int i;
  232 
  233         for (i = 0; i < cac_cd.cd_ndevs; i++) {
  234                 if ((sc = device_lookup_private(&cac_cd, i)) == NULL)
  235                         continue;
  236                 memset(tbuf, 0, sizeof(tbuf));
  237                 tbuf[0] = 1;
  238                 cac_cmd(sc, CAC_CMD_FLUSH_CACHE, tbuf, sizeof(tbuf), 0, 0,
  239                     CAC_CCB_DATA_OUT, NULL);
  240         }
  241 }
  242 
  243 /*
  244  * Print autoconfiguration message for a sub-device.
  245  */
  246 static int
  247 cac_print(void *aux, const char *pnp)
  248 {
  249         struct cac_attach_args *caca;
  250 
  251         caca = (struct cac_attach_args *)aux;
  252 
  253         if (pnp != NULL)
  254                 aprint_normal("block device at %s", pnp);
  255         aprint_normal(" unit %d", caca->caca_unit);
  256         return (UNCONF);
  257 }
  258 
  259 /*
  260  * Handle an interrupt from the controller: process finished CCBs and
  261  * dequeue any waiting CCBs.
  262  */
  263 int
  264 cac_intr(void *cookie)
  265 {
  266         struct cac_softc *sc;
  267         struct cac_ccb *ccb;
  268         int rv;
  269 
  270         sc = (struct cac_softc *)cookie;
  271 
  272         mutex_enter(&sc->sc_mutex);
  273 
  274         if ((*sc->sc_cl.cl_intr_pending)(sc)) {
  275                 while ((ccb = (*sc->sc_cl.cl_completed)(sc)) != NULL) {
  276                         cac_ccb_done(sc, ccb);
  277                         cac_ccb_start(sc, NULL);
  278                 }
  279                 rv = 1;
  280         } else
  281                 rv = 0;
  282 
  283         mutex_exit(&sc->sc_mutex);
  284 
  285         return (rv);
  286 }
  287 
  288 /*
  289  * Execute a [polled] command.
  290  */
  291 int
  292 cac_cmd(struct cac_softc *sc, int command, void *data, int datasize,
  293         int drive, int blkno, int flags, struct cac_context *context)
  294 {
  295         struct cac_ccb *ccb;
  296         struct cac_sgb *sgb;
  297         int i, rv, size, nsegs;
  298 
  299         size = 0;
  300 
  301         if ((ccb = cac_ccb_alloc(sc, 1)) == NULL) {
  302                 aprint_error_dev(&sc->sc_dv, "unable to alloc CCB");
  303                 return (EAGAIN);
  304         }
  305 
  306         if ((flags & (CAC_CCB_DATA_IN | CAC_CCB_DATA_OUT)) != 0) {
  307                 bus_dmamap_load(sc->sc_dmat, ccb->ccb_dmamap_xfer,
  308                     (void *)data, datasize, NULL, BUS_DMA_NOWAIT |
  309                     BUS_DMA_STREAMING | ((flags & CAC_CCB_DATA_IN) ?
  310                     BUS_DMA_READ : BUS_DMA_WRITE));
  311 
  312                 bus_dmamap_sync(sc->sc_dmat, ccb->ccb_dmamap_xfer, 0, datasize,
  313                     (flags & CAC_CCB_DATA_IN) != 0 ? BUS_DMASYNC_PREREAD :
  314                     BUS_DMASYNC_PREWRITE);
  315 
  316                 sgb = ccb->ccb_seg;
  317                 nsegs = min(ccb->ccb_dmamap_xfer->dm_nsegs, CAC_SG_SIZE);
  318 
  319                 for (i = 0; i < nsegs; i++, sgb++) {
  320                         size += ccb->ccb_dmamap_xfer->dm_segs[i].ds_len;
  321                         sgb->length =
  322                             htole32(ccb->ccb_dmamap_xfer->dm_segs[i].ds_len);
  323                         sgb->addr =
  324                             htole32(ccb->ccb_dmamap_xfer->dm_segs[i].ds_addr);
  325                 }
  326         } else {
  327                 size = datasize;
  328                 nsegs = 0;
  329         }
  330 
  331         ccb->ccb_hdr.drive = drive;
  332         ccb->ccb_hdr.priority = 0;
  333         ccb->ccb_hdr.size = htole16((sizeof(struct cac_req) +
  334             sizeof(struct cac_sgb) * CAC_SG_SIZE) >> 2);
  335 
  336         ccb->ccb_req.next = 0;
  337         ccb->ccb_req.error = 0;
  338         ccb->ccb_req.reserved = 0;
  339         ccb->ccb_req.bcount = htole16(howmany(size, DEV_BSIZE));
  340         ccb->ccb_req.command = command;
  341         ccb->ccb_req.sgcount = nsegs;
  342         ccb->ccb_req.blkno = htole32(blkno);
  343 
  344         ccb->ccb_flags = flags;
  345         ccb->ccb_datasize = size;
  346 
  347         mutex_enter(&sc->sc_mutex);
  348 
  349         if (context == NULL) {
  350                 memset(&ccb->ccb_context, 0, sizeof(struct cac_context));
  351 
  352                 /* Synchronous commands musn't wait. */
  353                 if ((*sc->sc_cl.cl_fifo_full)(sc)) {
  354                         cac_ccb_free(sc, ccb);
  355                         rv = EAGAIN;
  356                 } else {
  357 #ifdef DIAGNOSTIC
  358                         ccb->ccb_flags |= CAC_CCB_ACTIVE;
  359 #endif
  360                         (*sc->sc_cl.cl_submit)(sc, ccb);
  361                         rv = cac_ccb_poll(sc, ccb, 2000);
  362                         cac_ccb_free(sc, ccb);
  363                 }
  364         } else {
  365                 memcpy(&ccb->ccb_context, context, sizeof(struct cac_context));
  366                 (void)cac_ccb_start(sc, ccb);
  367                 rv = 0;
  368         }
  369 
  370         mutex_exit(&sc->sc_mutex);
  371         return (rv);
  372 }
  373 
  374 /*
  375  * Wait for the specified CCB to complete.
  376  */
  377 static int
  378 cac_ccb_poll(struct cac_softc *sc, struct cac_ccb *wantccb, int timo)
  379 {
  380         struct cac_ccb *ccb;
  381 
  382         KASSERT(mutex_owned(&sc->sc_mutex));
  383 
  384         timo *= 1000;
  385 
  386         do {
  387                 for (; timo != 0; timo--) {
  388                         ccb = (*sc->sc_cl.cl_completed)(sc);
  389                         if (ccb != NULL)
  390                                 break;
  391                         DELAY(1);
  392                 }
  393 
  394                 if (timo == 0) {
  395                         printf("%s: timeout\n", device_xname(&sc->sc_dv));
  396                         return (EBUSY);
  397                 }
  398                 cac_ccb_done(sc, ccb);
  399         } while (ccb != wantccb);
  400 
  401         return (0);
  402 }
  403 
  404 /*
  405  * Enqueue the specified command (if any) and attempt to start all enqueued
  406  * commands.
  407  */
  408 static int
  409 cac_ccb_start(struct cac_softc *sc, struct cac_ccb *ccb)
  410 {
  411 
  412         KASSERT(mutex_owned(&sc->sc_mutex));
  413 
  414         if (ccb != NULL)
  415                 SIMPLEQ_INSERT_TAIL(&sc->sc_ccb_queue, ccb, ccb_chain);
  416 
  417         while ((ccb = SIMPLEQ_FIRST(&sc->sc_ccb_queue)) != NULL) {
  418                 if ((*sc->sc_cl.cl_fifo_full)(sc))
  419                         return (EAGAIN);
  420                 SIMPLEQ_REMOVE_HEAD(&sc->sc_ccb_queue, ccb_chain);
  421 #ifdef DIAGNOSTIC
  422                 ccb->ccb_flags |= CAC_CCB_ACTIVE;
  423 #endif
  424                 (*sc->sc_cl.cl_submit)(sc, ccb);
  425         }
  426 
  427         return (0);
  428 }
  429 
  430 /*
  431  * Process a finished CCB.
  432  */
  433 static void
  434 cac_ccb_done(struct cac_softc *sc, struct cac_ccb *ccb)
  435 {
  436         struct device *dv;
  437         void *context;
  438         int error;
  439 
  440         error = 0;
  441 
  442         KASSERT(mutex_owned(&sc->sc_mutex));
  443 
  444 #ifdef DIAGNOSTIC
  445         if ((ccb->ccb_flags & CAC_CCB_ACTIVE) == 0)
  446                 panic("cac_ccb_done: CCB not active");
  447         ccb->ccb_flags &= ~CAC_CCB_ACTIVE;
  448 #endif
  449 
  450         if ((ccb->ccb_flags & (CAC_CCB_DATA_IN | CAC_CCB_DATA_OUT)) != 0) {
  451                 bus_dmamap_sync(sc->sc_dmat, ccb->ccb_dmamap_xfer, 0,
  452                     ccb->ccb_datasize, ccb->ccb_flags & CAC_CCB_DATA_IN ?
  453                     BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);
  454                 bus_dmamap_unload(sc->sc_dmat, ccb->ccb_dmamap_xfer);
  455         }
  456 
  457         error = ccb->ccb_req.error;
  458         if (ccb->ccb_context.cc_handler != NULL) {
  459                 dv = ccb->ccb_context.cc_dv;
  460                 context = ccb->ccb_context.cc_context;
  461                 cac_ccb_free(sc, ccb);
  462                 (*ccb->ccb_context.cc_handler)(dv, context, error);
  463         } else {
  464                 if ((error & CAC_RET_SOFT_ERROR) != 0)
  465                         aprint_error_dev(&sc->sc_dv, "soft error; array may be degraded\n");
  466                 if ((error & CAC_RET_HARD_ERROR) != 0)
  467                         aprint_error_dev(&sc->sc_dv, "hard error\n");
  468                 if ((error & CAC_RET_CMD_REJECTED) != 0) {
  469                         error = 1;
  470                         aprint_error_dev(&sc->sc_dv, "invalid request\n");
  471                 }
  472         }
  473 }
  474 
  475 /*
  476  * Allocate a CCB.
  477  */
  478 static struct cac_ccb *
  479 cac_ccb_alloc(struct cac_softc *sc, int nosleep)
  480 {
  481         struct cac_ccb *ccb;
  482 
  483         mutex_enter(&sc->sc_mutex);
  484 
  485         for (;;) {
  486                 if ((ccb = SIMPLEQ_FIRST(&sc->sc_ccb_free)) != NULL) {
  487                         SIMPLEQ_REMOVE_HEAD(&sc->sc_ccb_free, ccb_chain);
  488                         break;
  489                 }
  490                 if (nosleep) {
  491                         ccb = NULL;
  492                         break;
  493                 }
  494                 cv_wait(&sc->sc_ccb_cv, &sc->sc_mutex);
  495         }
  496 
  497         mutex_exit(&sc->sc_mutex);
  498         return (ccb);
  499 }
  500 
  501 /*
  502  * Put a CCB onto the freelist.
  503  */
  504 static void
  505 cac_ccb_free(struct cac_softc *sc, struct cac_ccb *ccb)
  506 {
  507 
  508         KASSERT(mutex_owned(&sc->sc_mutex));
  509 
  510         ccb->ccb_flags = 0;
  511         if (SIMPLEQ_EMPTY(&sc->sc_ccb_free))
  512                 cv_signal(&sc->sc_ccb_cv);
  513         SIMPLEQ_INSERT_HEAD(&sc->sc_ccb_free, ccb, ccb_chain);
  514 }
  515 
  516 /*
  517  * Board specific linkage shared between multiple bus types.
  518  */
  519 
  520 static int
  521 cac_l0_fifo_full(struct cac_softc *sc)
  522 {
  523 
  524         KASSERT(mutex_owned(&sc->sc_mutex));
  525 
  526         return (cac_inl(sc, CAC_REG_CMD_FIFO) == 0);
  527 }
  528 
  529 static void
  530 cac_l0_submit(struct cac_softc *sc, struct cac_ccb *ccb)
  531 {
  532 
  533         KASSERT(mutex_owned(&sc->sc_mutex));
  534 
  535         bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap,
  536             (char *)ccb - (char *)sc->sc_ccbs,
  537             sizeof(struct cac_ccb), BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
  538         cac_outl(sc, CAC_REG_CMD_FIFO, ccb->ccb_paddr);
  539 }
  540 
  541 static struct cac_ccb *
  542 cac_l0_completed(struct cac_softc *sc)
  543 {
  544         struct cac_ccb *ccb;
  545         paddr_t off;
  546 
  547         KASSERT(mutex_owned(&sc->sc_mutex));
  548 
  549         if ((off = cac_inl(sc, CAC_REG_DONE_FIFO)) == 0)
  550                 return (NULL);
  551 
  552         if ((off & 3) != 0)
  553                 aprint_error_dev(&sc->sc_dv, "failed command list returned: %lx\n",
  554                     (long)off);
  555 
  556         off = (off & ~3) - sc->sc_ccbs_paddr;
  557         ccb = (struct cac_ccb *)((char *)sc->sc_ccbs + off);
  558 
  559         bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap, off, sizeof(struct cac_ccb),
  560             BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD);
  561 
  562         if ((off & 3) != 0 && ccb->ccb_req.error == 0)
  563                 ccb->ccb_req.error = CAC_RET_CMD_REJECTED;
  564 
  565         return (ccb);
  566 }
  567 
  568 static int
  569 cac_l0_intr_pending(struct cac_softc *sc)
  570 {
  571 
  572         KASSERT(mutex_owned(&sc->sc_mutex));
  573 
  574         return (cac_inl(sc, CAC_REG_INTR_PENDING) & CAC_INTR_ENABLE);
  575 }
  576 
  577 static void
  578 cac_l0_intr_enable(struct cac_softc *sc, int state)
  579 {
  580 
  581         KASSERT(mutex_owned(&sc->sc_mutex));
  582 
  583         cac_outl(sc, CAC_REG_INTR_MASK,
  584             state ? CAC_INTR_ENABLE : CAC_INTR_DISABLE);
  585 }
  586 
  587 #if NBIO > 0
  588 const int cac_level[] = { 0, 4, 1, 5, 51, 7 };
  589 const int cac_stat[] = { BIOC_SVONLINE, BIOC_SVOFFLINE, BIOC_SVOFFLINE,
  590     BIOC_SVDEGRADED, BIOC_SVREBUILD, BIOC_SVREBUILD, BIOC_SVDEGRADED,
  591     BIOC_SVDEGRADED, BIOC_SVINVALID, BIOC_SVINVALID, BIOC_SVBUILDING,
  592     BIOC_SVOFFLINE, BIOC_SVBUILDING };
  593 
  594 int
  595 cac_ioctl(struct device *dev, u_long cmd, void *addr)
  596 {
  597         struct cac_softc        *sc = (struct cac_softc *)dev;
  598         struct bioc_inq *bi;
  599         struct bioc_disk *bd;
  600         cac_lock_t lock;
  601         int error = 0;
  602 
  603         lock = CAC_LOCK(sc);
  604         switch (cmd) {
  605         case BIOCINQ:
  606                 bi = (struct bioc_inq *)addr;
  607                 strlcpy(bi->bi_dev, device_xname(&sc->sc_dv), sizeof(bi->bi_dev));
  608                 bi->bi_novol = sc->sc_nunits;
  609                 bi->bi_nodisk = 0;
  610                 break;
  611 
  612         case BIOCVOL:
  613                 error = cac_ioctl_vol(sc, (struct bioc_vol *)addr);
  614                 break;
  615 
  616         case BIOCDISK:
  617         case BIOCDISK_NOVOL:
  618                 bd = (struct bioc_disk *)addr;
  619                 if (bd->bd_volid > sc->sc_nunits) {
  620                         error = EINVAL;
  621                         break;
  622                 }
  623                 /* No disk information yet */
  624                 break;
  625 
  626         case BIOCBLINK:
  627         case BIOCALARM:
  628         case BIOCSETSTATE:
  629         default:
  630                 error = EINVAL;
  631         }
  632         CAC_UNLOCK(sc, lock);
  633 
  634         return (error);
  635 }
  636 
  637 int
  638 cac_ioctl_vol(struct cac_softc *sc, struct bioc_vol *bv)
  639 {
  640         struct cac_drive_info dinfo;
  641         struct cac_drive_status dstatus;
  642         u_int32_t blks;
  643 
  644         if (bv->bv_volid > sc->sc_nunits) {
  645                 return EINVAL;
  646         }
  647         if (cac_cmd(sc, CAC_CMD_GET_LOG_DRV_INFO, &dinfo, sizeof(dinfo),
  648             bv->bv_volid, 0, CAC_CCB_DATA_IN, NULL)) {
  649                 return EIO;
  650         }
  651         if (cac_cmd(sc, CAC_CMD_SENSE_DRV_STATUS, &dstatus, sizeof(dstatus),
  652             bv->bv_volid, 0, CAC_CCB_DATA_IN, NULL)) {
  653                 return EIO;
  654         }
  655         blks = CAC_GET2(dinfo.ncylinders) * CAC_GET1(dinfo.nheads) *
  656             CAC_GET1(dinfo.nsectors);
  657         bv->bv_size = (off_t)blks * CAC_GET2(dinfo.secsize);
  658         bv->bv_level = cac_level[CAC_GET1(dinfo.mirror)];       /*XXX limit check */
  659         bv->bv_nodisk = 0;              /* XXX */
  660         bv->bv_status = 0;              /* XXX */
  661         bv->bv_percent = -1;
  662         bv->bv_seconds = 0;
  663         if (dstatus.stat < sizeof(cac_stat)/sizeof(cac_stat[0]))
  664                 bv->bv_status = cac_stat[dstatus.stat];
  665         if (bv->bv_status == BIOC_SVREBUILD ||
  666             bv->bv_status == BIOC_SVBUILDING)
  667                 bv->bv_percent = ((blks - CAC_GET4(dstatus.prog)) * 1000ULL) /
  668                     blks;
  669         return 0;
  670 }
  671 
  672 int
  673 cac_create_sensors(struct cac_softc *sc)
  674 {
  675         int                     i;
  676         int nsensors = sc->sc_nunits;
  677 
  678         sc->sc_sme = sysmon_envsys_create();
  679         sc->sc_sensor = malloc(sizeof(envsys_data_t) * nsensors,
  680             M_DEVBUF, M_NOWAIT | M_ZERO);
  681         if (sc->sc_sensor == NULL) {
  682                 aprint_error_dev(&sc->sc_dv, "can't allocate envsys_data_t\n");
  683                 return(ENOMEM);
  684         }
  685 
  686         for (i = 0; i < nsensors; i++) {
  687                 sc->sc_sensor[i].units = ENVSYS_DRIVE;
  688                 sc->sc_sensor[i].monitor = true;
  689                 /* Enable monitoring for drive state changes */
  690                 sc->sc_sensor[i].flags |= ENVSYS_FMONSTCHANGED;
  691                 /* logical drives */
  692                 snprintf(sc->sc_sensor[i].desc,
  693                     sizeof(sc->sc_sensor[i].desc), "%s:%d",
  694                     device_xname(&sc->sc_dv), i);
  695                 if (sysmon_envsys_sensor_attach(sc->sc_sme,
  696                     &sc->sc_sensor[i]))
  697                         goto out;
  698         }
  699         sc->sc_sme->sme_name = device_xname(&sc->sc_dv);
  700         sc->sc_sme->sme_cookie = sc;
  701         sc->sc_sme->sme_refresh = cac_sensor_refresh;
  702         if (sysmon_envsys_register(sc->sc_sme)) {
  703                 aprint_error_dev(&sc->sc_dv, "unable to register with sysmon\n");
  704                 return(1);
  705         }
  706         return (0);
  707 
  708 out:
  709         free(sc->sc_sensor, M_DEVBUF);
  710         sysmon_envsys_destroy(sc->sc_sme);
  711         return EINVAL;
  712 }
  713 
  714 void
  715 cac_sensor_refresh(struct sysmon_envsys *sme, envsys_data_t *edata)
  716 {
  717         struct cac_softc        *sc = sme->sme_cookie;
  718         struct bioc_vol         bv;
  719         int s;
  720 
  721         if (edata->sensor >= sc->sc_nunits)
  722                 return;
  723 
  724         bzero(&bv, sizeof(bv));
  725         bv.bv_volid = edata->sensor;
  726         s = splbio();
  727         if (cac_ioctl_vol(sc, &bv)) {
  728                 splx(s);
  729                 return;
  730         }
  731         splx(s);
  732 
  733         switch(bv.bv_status) {
  734         case BIOC_SVOFFLINE:
  735                 edata->value_cur = ENVSYS_DRIVE_FAIL;
  736                 edata->state = ENVSYS_SCRITICAL;
  737                 break;
  738 
  739         case BIOC_SVDEGRADED:
  740                 edata->value_cur = ENVSYS_DRIVE_PFAIL;
  741                 edata->state = ENVSYS_SCRITICAL;
  742                 break;
  743 
  744         case BIOC_SVSCRUB:
  745         case BIOC_SVONLINE:
  746                 edata->value_cur = ENVSYS_DRIVE_ONLINE;
  747                 edata->state = ENVSYS_SVALID;
  748                 break;
  749 
  750         case BIOC_SVREBUILD:
  751         case BIOC_SVBUILDING:
  752                 edata->value_cur = ENVSYS_DRIVE_REBUILD;
  753                 edata->state = ENVSYS_SVALID;
  754                 break;
  755 
  756         case BIOC_SVINVALID:
  757                 /* FALLTRHOUGH */
  758         default:
  759                 edata->value_cur = 0; /* unknown */
  760                 edata->state = ENVSYS_SINVALID;
  761         }
  762 }
  763 #endif /* NBIO > 0 */

Cache object: 08bff9558aa2e4ddb64b348738cd8940


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