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 /*      $OpenBSD: cac.c,v 1.76 2022/04/16 19:19:59 naddy Exp $  */
    2 /*      $NetBSD: cac.c,v 1.15 2000/11/08 19:20:35 ad Exp $      */
    3 
    4 /*
    5  * Copyright (c) 2001,2003 Michael Shalayeff
    6  * All rights reserved.
    7  *
    8  * The SCSI emulation layer is derived from gdt(4) driver,
    9  * Copyright (c) 1999, 2000 Niklas Hallqvist. All rights reserved.
   10  *
   11  * Redistribution and use in source and binary forms, with or without
   12  * modification, are permitted provided that the following conditions
   13  * are met:
   14  * 1. Redistributions of source code must retain the above copyright
   15  *    notice, this list of conditions and the following disclaimer.
   16  * 2. Redistributions in binary form must reproduce the above copyright
   17  *    notice, this list of conditions and the following disclaimer in the
   18  *    documentation and/or other materials provided with the distribution.
   19  *
   20  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   21  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   22  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   23  * IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT,
   24  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
   25  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
   26  * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
   28  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
   29  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
   30  * THE POSSIBILITY OF SUCH DAMAGE.
   31  */
   32 /*-
   33  * Copyright (c) 2000 The NetBSD Foundation, Inc.
   34  * All rights reserved.
   35  *
   36  * This code is derived from software contributed to The NetBSD Foundation
   37  * by Andrew Doran.
   38  *
   39  * Redistribution and use in source and binary forms, with or without
   40  * modification, are permitted provided that the following conditions
   41  * are met:
   42  * 1. Redistributions of source code must retain the above copyright
   43  *    notice, this list of conditions and the following disclaimer.
   44  * 2. Redistributions in binary form must reproduce the above copyright
   45  *    notice, this list of conditions and the following disclaimer in the
   46  *    documentation and/or other materials provided with the distribution.
   47  *
   48  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
   49  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   50  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   51  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
   52  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   53  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   54  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   55  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   56  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   57  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   58  * POSSIBILITY OF SUCH DAMAGE.
   59  */
   60 
   61 /*
   62  * Driver for Compaq array controllers.
   63  */
   64 
   65 #include "bio.h"
   66 
   67 /* #define      CAC_DEBUG */
   68 
   69 #include <sys/param.h>
   70 #include <sys/systm.h>
   71 #include <sys/kernel.h>
   72 #include <sys/ioctl.h>
   73 #include <sys/device.h>
   74 #include <sys/queue.h>
   75 #include <sys/buf.h>
   76 #include <sys/endian.h>
   77 #include <sys/malloc.h>
   78 #include <sys/pool.h>
   79 
   80 #include <machine/bus.h>
   81 
   82 #include <scsi/scsi_all.h>
   83 #include <scsi/scsi_disk.h>
   84 #include <scsi/scsiconf.h>
   85 
   86 #include <dev/ic/cacreg.h>
   87 #include <dev/ic/cacvar.h>
   88 
   89 #if NBIO > 0
   90 #include <dev/biovar.h>
   91 #endif
   92 #include <sys/sensors.h>
   93 
   94 struct cfdriver cac_cd = {
   95         NULL, "cac", DV_DULL
   96 };
   97 
   98 void    cac_scsi_cmd(struct scsi_xfer *);
   99 
  100 const struct scsi_adapter cac_switch = {
  101         cac_scsi_cmd, NULL, NULL, NULL, NULL
  102 };
  103 
  104 void    *cac_ccb_alloc(void *);
  105 void    cac_ccb_done(struct cac_softc *, struct cac_ccb *);
  106 void    cac_ccb_free(void *, void *);
  107 int     cac_ccb_poll(struct cac_softc *, struct cac_ccb *, int);
  108 int     cac_ccb_start(struct cac_softc *, struct cac_ccb *);
  109 int     cac_cmd(struct cac_softc *sc, int command, void *data, int datasize,
  110         int drive, int blkno, int flags, struct scsi_xfer *xs);
  111 int     cac_get_dinfo(struct cac_softc *sc, int target);
  112 
  113 struct  cac_ccb *cac_l0_completed(struct cac_softc *);
  114 int     cac_l0_fifo_full(struct cac_softc *);
  115 void    cac_l0_intr_enable(struct cac_softc *, int);
  116 int     cac_l0_intr_pending(struct cac_softc *);
  117 void    cac_l0_submit(struct cac_softc *, struct cac_ccb *);
  118 
  119 #if NBIO > 0
  120 int     cac_ioctl(struct device *, u_long, caddr_t);
  121 int     cac_ioctl_vol(struct cac_softc *, struct bioc_vol *);
  122 
  123 #ifndef SMALL_KERNEL
  124 int     cac_create_sensors(struct cac_softc *);
  125 void    cac_sensor_refresh(void *);
  126 #endif
  127 #endif /* NBIO > 0 */
  128 
  129 const
  130 struct cac_linkage cac_l0 = {
  131         cac_l0_completed,
  132         cac_l0_fifo_full,
  133         cac_l0_intr_enable,
  134         cac_l0_intr_pending,
  135         cac_l0_submit
  136 };
  137 
  138 /*
  139  * Initialise our interface to the controller.
  140  */
  141 int
  142 cac_init(struct cac_softc *sc, int startfw)
  143 {
  144         struct scsibus_attach_args saa;
  145         struct cac_controller_info cinfo;
  146         int error, rseg, size, i;
  147         bus_dma_segment_t seg[1];
  148         struct cac_ccb *ccb;
  149 
  150         SIMPLEQ_INIT(&sc->sc_ccb_free);
  151         SIMPLEQ_INIT(&sc->sc_ccb_queue);
  152         mtx_init(&sc->sc_ccb_mtx, IPL_BIO);
  153         scsi_iopool_init(&sc->sc_iopool, sc, cac_ccb_alloc, cac_ccb_free);
  154 
  155         size = sizeof(struct cac_ccb) * CAC_MAX_CCBS;
  156 
  157         if ((error = bus_dmamem_alloc(sc->sc_dmat, size, PAGE_SIZE, 0, seg, 1,
  158             &rseg, BUS_DMA_NOWAIT | BUS_DMA_ZERO)) != 0) {
  159                 printf("%s: unable to allocate CCBs, error = %d\n",
  160                     sc->sc_dv.dv_xname, error);
  161                 return (-1);
  162         }
  163 
  164         if ((error = bus_dmamem_map(sc->sc_dmat, seg, rseg, size,
  165             &sc->sc_ccbs, BUS_DMA_NOWAIT | BUS_DMA_COHERENT)) != 0) {
  166                 printf("%s: unable to map CCBs, error = %d\n",
  167                     sc->sc_dv.dv_xname, error);
  168                 return (-1);
  169         }
  170 
  171         if ((error = bus_dmamap_create(sc->sc_dmat, size, 1, size, 0,
  172             BUS_DMA_NOWAIT, &sc->sc_dmamap)) != 0) {
  173                 printf("%s: unable to create CCB DMA map, error = %d\n",
  174                     sc->sc_dv.dv_xname, error);
  175                 return (-1);
  176         }
  177 
  178         if ((error = bus_dmamap_load(sc->sc_dmat, sc->sc_dmamap, sc->sc_ccbs,
  179             size, NULL, BUS_DMA_NOWAIT)) != 0) {
  180                 printf("%s: unable to load CCB DMA map, error = %d\n",
  181                     sc->sc_dv.dv_xname, error);
  182                 return (-1);
  183         }
  184 
  185         sc->sc_ccbs_paddr = sc->sc_dmamap->dm_segs[0].ds_addr;
  186         ccb = (struct cac_ccb *)sc->sc_ccbs;
  187 
  188         for (i = 0; i < CAC_MAX_CCBS; i++, ccb++) {
  189                 /* Create the DMA map for this CCB's data */
  190                 error = bus_dmamap_create(sc->sc_dmat, CAC_MAX_XFER,
  191                     CAC_SG_SIZE, CAC_MAX_XFER, 0,
  192                     BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW,
  193                     &ccb->ccb_dmamap_xfer);
  194 
  195                 if (error) {
  196                         printf("%s: can't create ccb dmamap (%d)\n",
  197                             sc->sc_dv.dv_xname, error);
  198                         break;
  199                 }
  200 
  201                 ccb->ccb_paddr = sc->sc_ccbs_paddr + i * sizeof(struct cac_ccb);
  202                 mtx_enter(&sc->sc_ccb_mtx);
  203                 SIMPLEQ_INSERT_TAIL(&sc->sc_ccb_free, ccb, ccb_chain);
  204                 mtx_leave(&sc->sc_ccb_mtx);
  205         }
  206 
  207         /* Start firmware background tasks, if needed. */
  208         if (startfw) {
  209                 if (cac_cmd(sc, CAC_CMD_START_FIRMWARE, &cinfo, sizeof(cinfo),
  210                     0, 0, CAC_CCB_DATA_IN, NULL)) {
  211                         printf("%s: CAC_CMD_START_FIRMWARE failed\n",
  212                             sc->sc_dv.dv_xname);
  213                         return (-1);
  214                 }
  215         }
  216 
  217         if (cac_cmd(sc, CAC_CMD_GET_CTRL_INFO, &cinfo, sizeof(cinfo), 0, 0,
  218             CAC_CCB_DATA_IN, NULL)) {
  219                 printf("%s: CAC_CMD_GET_CTRL_INFO failed\n",
  220                     sc->sc_dv.dv_xname);
  221                 return (-1);
  222         }
  223 
  224         if (!cinfo.num_drvs) {
  225                 printf("%s: no volumes defined\n", sc->sc_dv.dv_xname);
  226                 return (-1);
  227         }
  228 
  229         sc->sc_nunits = cinfo.num_drvs;
  230         sc->sc_dinfos = mallocarray(cinfo.num_drvs,
  231             sizeof(struct cac_drive_info), M_DEVBUF, M_NOWAIT | M_ZERO);
  232         if (sc->sc_dinfos == NULL) {
  233                 printf("%s: cannot allocate memory for drive_info\n",
  234                     sc->sc_dv.dv_xname);
  235                 return (-1);
  236         }
  237 
  238         saa.saa_adapter_softc = sc;
  239         saa.saa_adapter = &cac_switch;
  240         saa.saa_adapter_target = SDEV_NO_ADAPTER_TARGET;
  241         saa.saa_adapter_buswidth = cinfo.num_drvs;
  242         saa.saa_luns = 8;
  243         saa.saa_openings = CAC_MAX_CCBS / sc->sc_nunits;
  244         if (saa.saa_openings < 4 )
  245                 saa.saa_openings = 4;
  246         saa.saa_pool = &sc->sc_iopool;
  247         saa.saa_quirks = saa.saa_flags = 0;
  248         saa.saa_wwpn = saa.saa_wwnn = 0;
  249 
  250         sc->sc_scsibus = (struct scsibus_softc *)config_found(&sc->sc_dv, &saa,
  251             scsiprint);
  252 
  253         (*sc->sc_cl->cl_intr_enable)(sc, 1);
  254 
  255 #if NBIO > 0
  256         if (bio_register(&sc->sc_dv, cac_ioctl) != 0)
  257                 printf("%s: controller registration failed\n",
  258                     sc->sc_dv.dv_xname);
  259         else
  260                 sc->sc_ioctl = cac_ioctl;
  261 
  262 #ifndef SMALL_KERNEL
  263         if (cac_create_sensors(sc) != 0)
  264                 printf("%s: unable to create sensors\n", sc->sc_dv.dv_xname);
  265 #endif
  266 #endif
  267 
  268 
  269         return (0);
  270 }
  271 
  272 int
  273 cac_flush(struct cac_softc *sc)
  274 {
  275         u_int8_t buf[512];
  276 
  277         memset(buf, 0, sizeof(buf));
  278         buf[0] = 1;
  279         return cac_cmd(sc, CAC_CMD_FLUSH_CACHE, buf, sizeof(buf), 0, 0,
  280             CAC_CCB_DATA_OUT, NULL);
  281 }
  282 
  283 /*
  284  * Handle an interrupt from the controller: process finished CCBs and
  285  * dequeue any waiting CCBs.
  286  */
  287 int
  288 cac_intr(void *v)
  289 {
  290         struct cac_softc *sc = v;
  291         struct cac_ccb *ccb;
  292         int istat, ret = 0;
  293 
  294         if (!(istat = (*sc->sc_cl->cl_intr_pending)(sc)))
  295                 return 0;
  296 
  297         if (istat & CAC_INTR_FIFO_NEMPTY)
  298                 while ((ccb = (*sc->sc_cl->cl_completed)(sc)) != NULL) {
  299                         ret = 1;
  300                         cac_ccb_done(sc, ccb);
  301                 }
  302         cac_ccb_start(sc, NULL);
  303 
  304         return (ret);
  305 }
  306 
  307 /*
  308  * Execute a [polled] command.
  309  */
  310 int
  311 cac_cmd(struct cac_softc *sc, int command, void *data, int datasize,
  312         int drive, int blkno, int flags, struct scsi_xfer *xs)
  313 {
  314         struct cac_ccb *ccb;
  315         struct cac_sgb *sgb;
  316         int i, rv, size, nsegs;
  317 
  318 #ifdef CAC_DEBUG
  319         printf("cac_cmd op=%x drv=%d blk=%d data=%p[%x] fl=%x xs=%p ",
  320             command, drive, blkno, data, datasize, flags, xs);
  321 #endif
  322 
  323         if (xs) {
  324                 ccb = xs->io;
  325                 /*
  326                  * The xs may have been restarted by the scsi layer, so
  327                  * ensure the ccb starts in the proper state.
  328                  */
  329                 ccb->ccb_flags = 0;
  330         } else {
  331                 /* Internal command. Need to get our own ccb. */
  332                 ccb = scsi_io_get(&sc->sc_iopool, SCSI_POLL | SCSI_NOSLEEP);
  333                 if (ccb == NULL)
  334                         return (EBUSY);
  335         }
  336 
  337         if ((flags & (CAC_CCB_DATA_IN | CAC_CCB_DATA_OUT)) != 0) {
  338                 bus_dmamap_load(sc->sc_dmat, ccb->ccb_dmamap_xfer,
  339                     (void *)data, datasize, NULL, BUS_DMA_NOWAIT);
  340 
  341                 bus_dmamap_sync(sc->sc_dmat, ccb->ccb_dmamap_xfer, 0,
  342                     ccb->ccb_dmamap_xfer->dm_mapsize,
  343                     (flags & CAC_CCB_DATA_IN) != 0 ? BUS_DMASYNC_PREREAD :
  344                     BUS_DMASYNC_PREWRITE);
  345 
  346                 sgb = ccb->ccb_seg;
  347                 nsegs = ccb->ccb_dmamap_xfer->dm_nsegs;
  348                 if (nsegs > CAC_SG_SIZE)
  349                         panic("cac_cmd: nsegs botch");
  350 
  351                 size = 0;
  352                 for (i = 0; i < nsegs; i++, sgb++) {
  353                         size += ccb->ccb_dmamap_xfer->dm_segs[i].ds_len;
  354                         sgb->length =
  355                             htole32(ccb->ccb_dmamap_xfer->dm_segs[i].ds_len);
  356                         sgb->addr =
  357                             htole32(ccb->ccb_dmamap_xfer->dm_segs[i].ds_addr);
  358                 }
  359         } else {
  360                 size = datasize;
  361                 nsegs = 0;
  362         }
  363 
  364         ccb->ccb_hdr.drive = drive;
  365         ccb->ccb_hdr.priority = 0;
  366         ccb->ccb_hdr.size = htole16((sizeof(struct cac_req) +
  367             sizeof(struct cac_sgb) * CAC_SG_SIZE) >> 2);
  368 
  369         ccb->ccb_req.next = 0;
  370         ccb->ccb_req.command = command;
  371         ccb->ccb_req.error = 0;
  372         ccb->ccb_req.blkno = htole32(blkno);
  373         ccb->ccb_req.bcount = htole16(howmany(size, DEV_BSIZE));
  374         ccb->ccb_req.sgcount = nsegs;
  375         ccb->ccb_req.reserved = 0;
  376 
  377         ccb->ccb_flags = flags;
  378         ccb->ccb_datasize = size;
  379         ccb->ccb_xs = xs;
  380 
  381         if (!xs || xs->flags & SCSI_POLL) {
  382                 /* Synchronous commands mustn't wait. */
  383                 mtx_enter(&sc->sc_ccb_mtx);
  384                 if ((*sc->sc_cl->cl_fifo_full)(sc)) {
  385                         mtx_leave(&sc->sc_ccb_mtx);
  386                         rv = EBUSY;
  387                 } else {
  388                         mtx_leave(&sc->sc_ccb_mtx);
  389                         ccb->ccb_flags |= CAC_CCB_ACTIVE;
  390                         (*sc->sc_cl->cl_submit)(sc, ccb);
  391                         rv = cac_ccb_poll(sc, ccb, 2000);
  392                 }
  393         } else
  394                 rv = cac_ccb_start(sc, ccb);
  395 
  396         if (xs == NULL)
  397                 scsi_io_put(&sc->sc_iopool, ccb);
  398 
  399         return (rv);
  400 }
  401 
  402 /*
  403  * Wait for the specified CCB to complete.  Must be called at splbio.
  404  */
  405 int
  406 cac_ccb_poll(struct cac_softc *sc, struct cac_ccb *wantccb, int timo)
  407 {
  408         struct cac_ccb *ccb;
  409         int t;
  410 
  411         t = timo * 100;
  412         do {
  413                 for (; t--; DELAY(10))
  414                         if ((ccb = (*sc->sc_cl->cl_completed)(sc)) != NULL)
  415                                 break;
  416                 if (t < 0) {
  417                         printf("%s: timeout\n", sc->sc_dv.dv_xname);
  418                         return (EBUSY);
  419                 }
  420                 cac_ccb_done(sc, ccb);
  421         } while (ccb != wantccb);
  422 
  423         return (0);
  424 }
  425 
  426 /*
  427  * Enqueue the specified command (if any) and attempt to start all enqueued
  428  * commands.
  429  */
  430 int
  431 cac_ccb_start(struct cac_softc *sc, struct cac_ccb *ccb)
  432 {
  433         if (ccb != NULL) {
  434                 mtx_enter(&sc->sc_ccb_mtx);
  435                 SIMPLEQ_INSERT_TAIL(&sc->sc_ccb_queue, ccb, ccb_chain);
  436                 mtx_leave(&sc->sc_ccb_mtx);
  437         }
  438 
  439         while (1) {
  440                 mtx_enter(&sc->sc_ccb_mtx);
  441                 if (SIMPLEQ_EMPTY(&sc->sc_ccb_queue) ||
  442                     (*sc->sc_cl->cl_fifo_full)(sc)) {
  443                         mtx_leave(&sc->sc_ccb_mtx);
  444                         break;
  445                 }
  446                 ccb = SIMPLEQ_FIRST(&sc->sc_ccb_queue);
  447                 SIMPLEQ_REMOVE_HEAD(&sc->sc_ccb_queue, ccb_chain);
  448                 mtx_leave(&sc->sc_ccb_mtx);
  449 
  450                 ccb->ccb_flags |= CAC_CCB_ACTIVE;
  451                 (*sc->sc_cl->cl_submit)(sc, ccb);
  452         }
  453 
  454         return (0);
  455 }
  456 
  457 /*
  458  * Process a finished CCB.
  459  */
  460 void
  461 cac_ccb_done(struct cac_softc *sc, struct cac_ccb *ccb)
  462 {
  463         struct scsi_xfer *xs = ccb->ccb_xs;
  464         int error = 0;
  465 
  466         if ((ccb->ccb_flags & CAC_CCB_ACTIVE) == 0) {
  467                 printf("%s: CCB not active, xs=%p\n", sc->sc_dv.dv_xname, xs);
  468                 if (xs) {
  469                         xs->error = XS_DRIVER_STUFFUP;
  470                         scsi_done(xs);
  471                 }
  472                 return;
  473         }
  474 
  475         if ((ccb->ccb_flags & (CAC_CCB_DATA_IN | CAC_CCB_DATA_OUT)) != 0) {
  476                 bus_dmamap_sync(sc->sc_dmat, ccb->ccb_dmamap_xfer, 0,
  477                     ccb->ccb_dmamap_xfer->dm_mapsize,
  478                     ccb->ccb_flags & CAC_CCB_DATA_IN ?
  479                     BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);
  480                 bus_dmamap_unload(sc->sc_dmat, ccb->ccb_dmamap_xfer);
  481         }
  482 
  483         if ((ccb->ccb_req.error & CAC_RET_SOFT_ERROR) != 0)
  484                 printf("%s: soft error; corrected\n", sc->sc_dv.dv_xname);
  485         if ((ccb->ccb_req.error & CAC_RET_HARD_ERROR) != 0) {
  486                 error = 1;
  487                 printf("%s: hard error\n", sc->sc_dv.dv_xname);
  488         }
  489         if ((ccb->ccb_req.error & CAC_RET_CMD_REJECTED) != 0) {
  490                 error = 1;
  491                 printf("%s: invalid request\n", sc->sc_dv.dv_xname);
  492         }
  493 
  494         if (xs) {
  495                 if (error)
  496                         xs->error = XS_DRIVER_STUFFUP;
  497                 else
  498                         xs->resid = 0;
  499 
  500                 scsi_done(xs);
  501         }
  502 }
  503 
  504 /*
  505  * Allocate a CCB.
  506  */
  507 void *
  508 cac_ccb_alloc(void *xsc)
  509 {
  510         struct cac_softc *sc = xsc;
  511         struct cac_ccb *ccb = NULL;
  512 
  513         mtx_enter(&sc->sc_ccb_mtx);
  514         if (SIMPLEQ_EMPTY(&sc->sc_ccb_free)) {
  515 #ifdef CAC_DEBUG
  516                 printf("%s: unable to alloc CCB\n", sc->sc_dv.dv_xname);
  517 #endif
  518         } else {
  519                 ccb = SIMPLEQ_FIRST(&sc->sc_ccb_free);
  520                 SIMPLEQ_REMOVE_HEAD(&sc->sc_ccb_free, ccb_chain);
  521         }
  522         mtx_leave(&sc->sc_ccb_mtx);
  523 
  524         return (ccb);
  525 }
  526 
  527 /*
  528  * Put a CCB onto the freelist.
  529  */
  530 void
  531 cac_ccb_free(void *xsc, void *xccb)
  532 {
  533         struct cac_softc *sc = xsc;
  534         struct cac_ccb *ccb = xccb;
  535 
  536         ccb->ccb_flags = 0;
  537 
  538         mtx_enter(&sc->sc_ccb_mtx);
  539         SIMPLEQ_INSERT_HEAD(&sc->sc_ccb_free, ccb, ccb_chain);
  540         mtx_leave(&sc->sc_ccb_mtx);
  541 }
  542 
  543 int
  544 cac_get_dinfo(struct cac_softc *sc, int target)
  545 {
  546         if (sc->sc_dinfos[target].ncylinders)
  547                 return (0);
  548 
  549         if (cac_cmd(sc, CAC_CMD_GET_LOG_DRV_INFO, &sc->sc_dinfos[target],
  550             sizeof(*sc->sc_dinfos), target, 0, CAC_CCB_DATA_IN, NULL)) {
  551                 printf("%s: CMD_GET_LOG_DRV_INFO failed\n",
  552                     sc->sc_dv.dv_xname);
  553                 return (-1);
  554         }
  555 
  556         return (0);
  557 }
  558 
  559 void
  560 cac_scsi_cmd(struct scsi_xfer *xs)
  561 {
  562         struct scsi_link *link = xs->sc_link;
  563         struct cac_softc *sc = link->bus->sb_adapter_softc;
  564         struct cac_drive_info *dinfo;
  565         struct scsi_inquiry_data inq;
  566         struct scsi_sense_data sd;
  567         struct scsi_read_cap_data rcd;
  568         u_int8_t target = link->target;
  569         u_int32_t blockno, blockcnt, size;
  570         struct scsi_rw *rw;
  571         struct scsi_rw_10 *rw10;
  572         int op, flags, s, error;
  573         const char *p;
  574 
  575         if (target >= sc->sc_nunits || link->lun != 0) {
  576                 xs->error = XS_DRIVER_STUFFUP;
  577                 scsi_done(xs);
  578                 return;
  579         }
  580 
  581         s = splbio();
  582         xs->error = XS_NOERROR;
  583         dinfo = &sc->sc_dinfos[target];
  584 
  585         switch (xs->cmd.opcode) {
  586         case TEST_UNIT_READY:
  587         case START_STOP:
  588 #if 0
  589         case VERIFY:
  590 #endif
  591                 break;
  592 
  593         case REQUEST_SENSE:
  594                 bzero(&sd, sizeof sd);
  595                 sd.error_code = SSD_ERRCODE_CURRENT;
  596                 sd.segment = 0;
  597                 sd.flags = SKEY_NO_SENSE;
  598                 *(u_int32_t*)sd.info = htole32(0);
  599                 sd.extra_len = 0;
  600                 scsi_copy_internal_data(xs, &sd, sizeof(sd));
  601                 break;
  602 
  603         case INQUIRY:
  604                 if (cac_get_dinfo(sc, target)) {
  605                         xs->error = XS_DRIVER_STUFFUP;
  606                         break;
  607                 }
  608                 bzero(&inq, sizeof inq);
  609                 inq.device = T_DIRECT;
  610                 inq.dev_qual2 = 0;
  611                 inq.version = SCSI_REV_2;
  612                 inq.response_format = SID_SCSI2_RESPONSE;
  613                 inq.additional_length = SID_SCSI2_ALEN;
  614                 inq.flags |= SID_CmdQue;
  615                 strlcpy(inq.vendor, "Compaq  ", sizeof inq.vendor);
  616                 switch (CAC_GET1(dinfo->mirror)) {
  617                 case 0: p = "RAID0";    break;
  618                 case 1: p = "RAID4";    break;
  619                 case 2: p = "RAID1";    break;
  620                 case 3: p = "RAID5";    break;
  621                 default:p = "<UNK>";    break;
  622                 }
  623                 snprintf(inq.product, sizeof inq.product, "%s vol  #%02d",
  624                     p, target);
  625                 strlcpy(inq.revision, "   ", sizeof inq.revision);
  626                 scsi_copy_internal_data(xs, &inq, sizeof(inq));
  627                 break;
  628 
  629         case READ_CAPACITY:
  630                 if (cac_get_dinfo(sc, target)) {
  631                         xs->error = XS_DRIVER_STUFFUP;
  632                         break;
  633                 }
  634                 bzero(&rcd, sizeof rcd);
  635                 _lto4b( CAC_GET2(dinfo->ncylinders) * CAC_GET1(dinfo->nheads) *
  636                     CAC_GET1(dinfo->nsectors) - 1, rcd.addr);
  637                 _lto4b(CAC_SECTOR_SIZE, rcd.length);
  638                 scsi_copy_internal_data(xs, &rcd, sizeof(rcd));
  639                 break;
  640 
  641         case PREVENT_ALLOW:
  642                 break;
  643 
  644         case SYNCHRONIZE_CACHE:
  645                 if (cac_flush(sc))
  646                         xs->error = XS_DRIVER_STUFFUP;
  647                 break;
  648 
  649         case READ_COMMAND:
  650         case READ_10:
  651         case WRITE_COMMAND:
  652         case WRITE_10:
  653 
  654                 flags = 0;
  655                 /* A read or write operation. */
  656                 if (xs->cmdlen == 6) {
  657                         rw = (struct scsi_rw *)&xs->cmd;
  658                         blockno = _3btol(rw->addr) &
  659                             (SRW_TOPADDR << 16 | 0xffff);
  660                         blockcnt = rw->length ? rw->length : 0x100;
  661                 } else {
  662                         rw10 = (struct scsi_rw_10 *)&xs->cmd;
  663                         blockno = _4btol(rw10->addr);
  664                         blockcnt = _2btol(rw10->length);
  665                 }
  666                 size = CAC_GET2(dinfo->ncylinders) *
  667                     CAC_GET1(dinfo->nheads) * CAC_GET1(dinfo->nsectors);
  668                 if (blockno >= size || blockno + blockcnt > size) {
  669                         printf("%s: out of bounds %u-%u >= %u\n",
  670                             sc->sc_dv.dv_xname, blockno, blockcnt, size);
  671                         xs->error = XS_DRIVER_STUFFUP;
  672                         break;
  673                 }
  674 
  675                 switch (xs->cmd.opcode) {
  676                 case READ_COMMAND:
  677                 case READ_10:
  678                         op = CAC_CMD_READ;
  679                         flags = CAC_CCB_DATA_IN;
  680                         break;
  681                 case WRITE_COMMAND:
  682                 case WRITE_10:
  683                         op = CAC_CMD_WRITE;
  684                         flags = CAC_CCB_DATA_OUT;
  685                         break;
  686                 }
  687 
  688                 if ((error = cac_cmd(sc, op, xs->data, blockcnt * DEV_BSIZE,
  689                     target, blockno, flags, xs))) {
  690                         splx(s);
  691                         if (error == EBUSY)
  692                                 xs->error = XS_BUSY;
  693                         else
  694                                 xs->error = XS_DRIVER_STUFFUP;
  695                         scsi_done(xs);
  696                         return;
  697                 }
  698 
  699                 splx(s);
  700                 return;
  701 
  702         default:
  703 #ifdef CAC_DEBUG
  704                 printf("unsupported scsi command %#x tgt %d ", xs->cmd.opcode, target);
  705 #endif
  706                 xs->error = XS_DRIVER_STUFFUP;
  707         }
  708 
  709         splx(s);
  710         scsi_done(xs);
  711 }
  712 
  713 /*
  714  * Board specific linkage shared between multiple bus types.
  715  */
  716 
  717 int
  718 cac_l0_fifo_full(struct cac_softc *sc)
  719 {
  720 
  721         return (cac_inl(sc, CAC_REG_CMD_FIFO) == 0);
  722 }
  723 
  724 void
  725 cac_l0_submit(struct cac_softc *sc, struct cac_ccb *ccb)
  726 {
  727 #ifdef CAC_DEBUG
  728         printf("submit-%lx ", ccb->ccb_paddr);
  729 #endif
  730         bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap, 0,
  731             sc->sc_dmamap->dm_mapsize,
  732             BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
  733         cac_outl(sc, CAC_REG_CMD_FIFO, ccb->ccb_paddr);
  734 }
  735 
  736 struct cac_ccb *
  737 cac_l0_completed(struct cac_softc *sc)
  738 {
  739         struct cac_ccb *ccb;
  740         paddr_t off, orig_off;
  741 
  742         if (!(off = cac_inl(sc, CAC_REG_DONE_FIFO)))
  743                 return NULL;
  744 #ifdef CAC_DEBUG
  745         printf("compl-%lx ", off);
  746 #endif
  747         orig_off = off;
  748 
  749         bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap, 0,
  750             sc->sc_dmamap->dm_mapsize,
  751             BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD);
  752 
  753         off = (off & ~3) - sc->sc_ccbs_paddr;
  754         ccb = (struct cac_ccb *)(sc->sc_ccbs + off);
  755 
  756         if (orig_off & 3 && ccb->ccb_req.error == 0)
  757                 ccb->ccb_req.error = CAC_RET_CMD_INVALID;
  758 
  759         return (ccb);
  760 }
  761 
  762 int
  763 cac_l0_intr_pending(struct cac_softc *sc)
  764 {
  765 
  766         return (cac_inl(sc, CAC_REG_INTR_PENDING));
  767 }
  768 
  769 void
  770 cac_l0_intr_enable(struct cac_softc *sc, int state)
  771 {
  772 
  773         cac_outl(sc, CAC_REG_INTR_MASK,
  774             state ? CAC_INTR_ENABLE : CAC_INTR_DISABLE);
  775 }
  776 
  777 #if NBIO > 0
  778 const int cac_level[] = { 0, 4, 1, 5, 51, 7 };
  779 const int cac_stat[] = { BIOC_SVONLINE, BIOC_SVOFFLINE, BIOC_SVOFFLINE,
  780     BIOC_SVDEGRADED, BIOC_SVREBUILD, BIOC_SVREBUILD, BIOC_SVDEGRADED,
  781     BIOC_SVDEGRADED, BIOC_SVINVALID, BIOC_SVINVALID, BIOC_SVBUILDING,
  782     BIOC_SVOFFLINE, BIOC_SVBUILDING };
  783 
  784 int
  785 cac_ioctl(struct device *dev, u_long cmd, caddr_t addr)
  786 {
  787         struct cac_softc *sc = (struct cac_softc *)dev;
  788         struct bioc_inq *bi;
  789         struct bioc_disk *bd;
  790         cac_lock_t lock;
  791         int error = 0;
  792 
  793         lock = CAC_LOCK(sc);
  794         switch (cmd) {
  795         case BIOCINQ:
  796                 bi = (struct bioc_inq *)addr;
  797                 strlcpy(bi->bi_dev, sc->sc_dv.dv_xname, sizeof(bi->bi_dev));
  798                 bi->bi_novol = sc->sc_nunits;
  799                 bi->bi_nodisk = 0;
  800                 break;
  801 
  802         case BIOCVOL:
  803                 error = cac_ioctl_vol(sc, (struct bioc_vol *)addr);
  804                 break;
  805 
  806         case BIOCDISK:
  807                 bd = (struct bioc_disk *)addr;
  808                 if (bd->bd_volid > sc->sc_nunits) {
  809                         error = EINVAL;
  810                         break;
  811                 }
  812                 /* No disk information yet */
  813                 break;
  814 
  815         case BIOCBLINK:
  816         case BIOCALARM:
  817         case BIOCSETSTATE:
  818         default:
  819                 error = ENOTTY;
  820         }
  821         CAC_UNLOCK(sc, lock);
  822 
  823         return (error);
  824 }
  825 
  826 int
  827 cac_ioctl_vol(struct cac_softc *sc, struct bioc_vol *bv)
  828 {
  829         struct cac_drive_info dinfo;
  830         struct cac_drive_status dstatus;
  831         u_int32_t blks;
  832 
  833         if (bv->bv_volid > sc->sc_nunits)
  834                 return (EINVAL);
  835         if (cac_cmd(sc, CAC_CMD_GET_LOG_DRV_INFO, &dinfo, sizeof(dinfo),
  836             bv->bv_volid, 0, CAC_CCB_DATA_IN, NULL))
  837                 return (EIO);
  838         if (cac_cmd(sc, CAC_CMD_SENSE_DRV_STATUS, &dstatus, sizeof(dstatus),
  839             bv->bv_volid, 0, CAC_CCB_DATA_IN, NULL))
  840                 return (EIO);
  841         bv->bv_status = BIOC_SVINVALID;
  842         blks = CAC_GET2(dinfo.ncylinders) * CAC_GET1(dinfo.nheads) *
  843             CAC_GET1(dinfo.nsectors);
  844         bv->bv_size = (off_t)blks * CAC_GET2(dinfo.secsize);
  845         bv->bv_level = cac_level[CAC_GET1(dinfo.mirror)];       /*XXX limit check */
  846         bv->bv_nodisk = 0;              /* XXX */
  847         bv->bv_status = 0;              /* XXX */
  848         bv->bv_percent = -1;
  849         bv->bv_seconds = 0;
  850         if (dstatus.stat < nitems(cac_stat))
  851                 bv->bv_status = cac_stat[dstatus.stat];
  852         if (bv->bv_status == BIOC_SVREBUILD ||
  853             bv->bv_status == BIOC_SVBUILDING)
  854                 bv->bv_percent = ((blks - CAC_GET4(dstatus.prog)) * 1000ULL) /
  855                     blks;
  856 
  857         return (0);
  858 }
  859 
  860 #ifndef SMALL_KERNEL
  861 int
  862 cac_create_sensors(struct cac_softc *sc)
  863 {
  864         struct device *dev;
  865         struct scsibus_softc *ssc = NULL;
  866         struct scsi_link *link;
  867         int i;
  868 
  869         TAILQ_FOREACH(dev, &alldevs, dv_list) {
  870                 if (dev->dv_parent != &sc->sc_dv)
  871                         continue;
  872 
  873                 /* check if this is the scsibus for the logical disks */
  874                 ssc = (struct scsibus_softc *)dev;
  875                 if (ssc == sc->sc_scsibus)
  876                         break;
  877                 ssc = NULL;
  878         }
  879 
  880         if (ssc == NULL)
  881                 return (1);
  882 
  883         sc->sc_sensors = mallocarray(sc->sc_nunits,
  884             sizeof(struct ksensor), M_DEVBUF, M_NOWAIT | M_ZERO);
  885         if (sc->sc_sensors == NULL)
  886                 return (1);
  887 
  888         strlcpy(sc->sc_sensordev.xname, sc->sc_dv.dv_xname,
  889             sizeof(sc->sc_sensordev.xname));
  890 
  891         for (i = 0; i < sc->sc_nunits; i++) {
  892                 link = scsi_get_link(ssc, i, 0);
  893                 if (link == NULL)
  894                         goto bad;
  895 
  896                 dev = link->device_softc;
  897 
  898                 sc->sc_sensors[i].type = SENSOR_DRIVE;
  899                 sc->sc_sensors[i].status = SENSOR_S_UNKNOWN;
  900 
  901                 strlcpy(sc->sc_sensors[i].desc, dev->dv_xname,
  902                     sizeof(sc->sc_sensors[i].desc));
  903 
  904                 sensor_attach(&sc->sc_sensordev, &sc->sc_sensors[i]);
  905         }
  906 
  907         if (sensor_task_register(sc, cac_sensor_refresh, 10) == NULL)
  908                 goto bad;
  909 
  910         sensordev_install(&sc->sc_sensordev);
  911 
  912         return (0);
  913 
  914 bad:
  915         free(sc->sc_sensors, M_DEVBUF,
  916             sc->sc_nunits * sizeof(struct ksensor));
  917 
  918         return (1);
  919 }
  920 
  921 void
  922 cac_sensor_refresh(void *arg)
  923 {
  924         struct cac_softc *sc = arg;
  925         struct bioc_vol bv;
  926         int i, s;
  927 
  928         for (i = 0; i < sc->sc_nunits; i++) {
  929                 bzero(&bv, sizeof(bv));
  930                 bv.bv_volid = i;
  931                 s = splbio();
  932                 if (cac_ioctl_vol(sc, &bv)) {
  933                         splx(s);
  934                         return;
  935                 }
  936                 splx(s);
  937 
  938                 switch (bv.bv_status) {
  939                 case BIOC_SVOFFLINE:
  940                         sc->sc_sensors[i].value = SENSOR_DRIVE_FAIL;
  941                         sc->sc_sensors[i].status = SENSOR_S_CRIT;
  942                         break;
  943 
  944                 case BIOC_SVDEGRADED:
  945                         sc->sc_sensors[i].value = SENSOR_DRIVE_PFAIL;
  946                         sc->sc_sensors[i].status = SENSOR_S_WARN;
  947                         break;
  948 
  949                 case BIOC_SVSCRUB:
  950                 case BIOC_SVONLINE:
  951                         sc->sc_sensors[i].value = SENSOR_DRIVE_ONLINE;
  952                         sc->sc_sensors[i].status = SENSOR_S_OK;
  953                         break;
  954 
  955                 case BIOC_SVREBUILD:
  956                 case BIOC_SVBUILDING:
  957                         sc->sc_sensors[i].value = SENSOR_DRIVE_REBUILD;
  958                         sc->sc_sensors[i].status = SENSOR_S_OK;
  959                         break;
  960 
  961                 case BIOC_SVINVALID:
  962                         /* FALLTRHOUGH */
  963                 default:
  964                         sc->sc_sensors[i].value = 0; /* unknown */
  965                         sc->sc_sensors[i].status = SENSOR_S_UNKNOWN;
  966                 }
  967         }
  968 }
  969 #endif /* SMALL_KERNEL */
  970 #endif /* NBIO > 0 */

Cache object: 1e94667123b0102fb37b0aee9c94d879


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