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/ciss.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: ciss.c,v 1.91 2022/04/16 19:19:59 naddy Exp $ */
    2 
    3 /*
    4  * Copyright (c) 2005,2006 Michael Shalayeff
    5  * All rights reserved.
    6  *
    7  * Permission to use, copy, modify, and distribute this software for any
    8  * purpose with or without fee is hereby granted, provided that the above
    9  * copyright notice and this permission notice appear in all copies.
   10  *
   11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
   12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
   13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
   14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
   15  * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER IN
   16  * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
   17  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
   18  */
   19 
   20 #include "bio.h"
   21 
   22 /* #define CISS_DEBUG */
   23 
   24 #include <sys/param.h>
   25 #include <sys/systm.h>
   26 #include <sys/buf.h>
   27 #include <sys/ioctl.h>
   28 #include <sys/device.h>
   29 #include <sys/kernel.h>
   30 #include <sys/malloc.h>
   31 
   32 #include <machine/bus.h>
   33 
   34 #include <scsi/scsi_all.h>
   35 #include <scsi/scsiconf.h>
   36 
   37 #include <dev/ic/cissreg.h>
   38 #include <dev/ic/cissvar.h>
   39 
   40 #if NBIO > 0
   41 #include <dev/biovar.h>
   42 #endif
   43 #include <sys/sensors.h>
   44 
   45 #ifdef CISS_DEBUG
   46 #define CISS_DPRINTF(m,a)       if (ciss_debug & (m)) printf a
   47 #define CISS_D_CMD      0x0001
   48 #define CISS_D_INTR     0x0002
   49 #define CISS_D_MISC     0x0004
   50 #define CISS_D_DMA      0x0008
   51 #define CISS_D_IOCTL    0x0010
   52 #define CISS_D_ERR      0x0020
   53 int ciss_debug = 0
   54 /*      | CISS_D_CMD */
   55 /*      | CISS_D_INTR */
   56 /*      | CISS_D_MISC */
   57 /*      | CISS_D_DMA */
   58 /*      | CISS_D_IOCTL */
   59 /*      | CISS_D_ERR */
   60         ;
   61 #else
   62 #define CISS_DPRINTF(m,a)       /* m, a */
   63 #endif
   64 
   65 struct cfdriver ciss_cd = {
   66         NULL, "ciss", DV_DULL
   67 };
   68 
   69 void    ciss_scsi_cmd(struct scsi_xfer *xs);
   70 int     ciss_scsi_ioctl(struct scsi_link *, u_long, caddr_t, int);
   71 
   72 const struct scsi_adapter ciss_switch = {
   73         ciss_scsi_cmd, NULL, NULL, NULL, ciss_scsi_ioctl
   74 };
   75 
   76 #if NBIO > 0
   77 int     ciss_ioctl(struct device *, u_long, caddr_t);
   78 #endif
   79 int     ciss_sync(struct ciss_softc *sc);
   80 void    ciss_heartbeat(void *v);
   81 #ifndef SMALL_KERNEL
   82 void    ciss_sensors(void *);
   83 #endif
   84 
   85 void *  ciss_get_ccb(void *);
   86 void    ciss_put_ccb(void *, void *);
   87 int     ciss_cmd(struct ciss_ccb *ccb, int flags, int wait);
   88 int     ciss_done(struct ciss_ccb *ccb);
   89 int     ciss_error(struct ciss_ccb *ccb);
   90 
   91 struct ciss_ld *ciss_pdscan(struct ciss_softc *sc, int ld);
   92 int     ciss_inq(struct ciss_softc *sc, struct ciss_inquiry *inq);
   93 int     ciss_ldmap(struct ciss_softc *sc);
   94 int     ciss_ldid(struct ciss_softc *, int, struct ciss_ldid *);
   95 int     ciss_ldstat(struct ciss_softc *, int, struct ciss_ldstat *);
   96 int     ciss_pdid(struct ciss_softc *, u_int8_t, struct ciss_pdid *, int);
   97 int     ciss_blink(struct ciss_softc *, int, int, int, struct ciss_blink *);
   98 
   99 void *
  100 ciss_get_ccb(void *xsc)
  101 {
  102         struct ciss_softc *sc = xsc;
  103         struct ciss_ccb *ccb;
  104 
  105         mtx_enter(&sc->sc_free_ccb_mtx);
  106         ccb = SLIST_FIRST(&sc->sc_free_ccb);
  107         if (ccb != NULL) {
  108                 SLIST_REMOVE_HEAD(&sc->sc_free_ccb, ccb_link);
  109                 ccb->ccb_state = CISS_CCB_READY;
  110                 ccb->ccb_xs = NULL;
  111         }
  112         mtx_leave(&sc->sc_free_ccb_mtx);
  113 
  114         return (ccb);
  115 }
  116 
  117 void
  118 ciss_put_ccb(void *xsc, void *xccb)
  119 {
  120         struct ciss_softc *sc = xsc;
  121         struct ciss_ccb *ccb = xccb;
  122 
  123         ccb->ccb_state = CISS_CCB_FREE;
  124         ccb->ccb_xs = NULL;
  125         ccb->ccb_data = NULL;
  126 
  127         mtx_enter(&sc->sc_free_ccb_mtx);
  128         SLIST_INSERT_HEAD(&sc->sc_free_ccb, ccb, ccb_link);
  129         mtx_leave(&sc->sc_free_ccb_mtx);
  130 }
  131 
  132 int
  133 ciss_attach(struct ciss_softc *sc)
  134 {
  135         struct scsibus_attach_args saa;
  136         struct scsibus_softc *scsibus;
  137         struct ciss_ccb *ccb;
  138         struct ciss_cmd *cmd;
  139         struct ciss_inquiry *inq;
  140         bus_dma_segment_t seg[1];
  141         int error, i, total, rseg, maxfer;
  142         ciss_lock_t lock;
  143         paddr_t pa;
  144 
  145         bus_space_read_region_4(sc->iot, sc->cfg_ioh, sc->cfgoff,
  146             (u_int32_t *)&sc->cfg, sizeof(sc->cfg) / 4);
  147 
  148         if (sc->cfg.signature != CISS_SIGNATURE) {
  149                 printf(": bad sign 0x%08x\n", sc->cfg.signature);
  150                 return -1;
  151         }
  152 
  153         if (!(sc->cfg.methods & CISS_METH_SIMPL)) {
  154                 printf(": not simple 0x%08x\n", sc->cfg.methods);
  155                 return -1;
  156         }
  157 
  158         sc->cfg.rmethod = CISS_METH_SIMPL;
  159         sc->cfg.paddr_lim = 0;                  /* 32bit addrs */
  160         sc->cfg.int_delay = 0;                  /* disable coalescing */
  161         sc->cfg.int_count = 0;
  162         strlcpy(sc->cfg.hostname, "HUMPPA", sizeof(sc->cfg.hostname));
  163         sc->cfg.driverf |= CISS_DRV_PRF;        /* enable prefetch */
  164         if (!sc->cfg.maxsg)
  165                 sc->cfg.maxsg = MAXPHYS / PAGE_SIZE;
  166 
  167         bus_space_write_region_4(sc->iot, sc->cfg_ioh, sc->cfgoff,
  168             (u_int32_t *)&sc->cfg, sizeof(sc->cfg) / 4);
  169         bus_space_barrier(sc->iot, sc->cfg_ioh, sc->cfgoff, sizeof(sc->cfg),
  170             BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE);
  171 
  172         bus_space_write_4(sc->iot, sc->ioh, CISS_IDB, CISS_IDB_CFG);
  173         bus_space_barrier(sc->iot, sc->ioh, CISS_IDB, 4,
  174             BUS_SPACE_BARRIER_WRITE);
  175         for (i = 1000; i--; DELAY(1000)) {
  176                 /* XXX maybe IDB is really 64bit? - hp dl380 needs this */
  177                 (void)bus_space_read_4(sc->iot, sc->ioh, CISS_IDB + 4);
  178                 if (!(bus_space_read_4(sc->iot, sc->ioh, CISS_IDB) & CISS_IDB_CFG))
  179                         break;
  180                 bus_space_barrier(sc->iot, sc->ioh, CISS_IDB, 4,
  181                     BUS_SPACE_BARRIER_READ);
  182         }
  183 
  184         if (bus_space_read_4(sc->iot, sc->ioh, CISS_IDB) & CISS_IDB_CFG) {
  185                 printf(": cannot set config\n");
  186                 return -1;
  187         }
  188 
  189         bus_space_read_region_4(sc->iot, sc->cfg_ioh, sc->cfgoff,
  190             (u_int32_t *)&sc->cfg, sizeof(sc->cfg) / 4);
  191 
  192         if (!(sc->cfg.amethod & CISS_METH_SIMPL)) {
  193                 printf(": cannot simplify 0x%08x\n", sc->cfg.amethod);
  194                 return -1;
  195         }
  196 
  197         /* i'm ready for you and i hope you're ready for me */
  198         for (i = 30000; i--; DELAY(1000)) {
  199                 if (bus_space_read_4(sc->iot, sc->cfg_ioh, sc->cfgoff +
  200                     offsetof(struct ciss_config, amethod)) & CISS_METH_READY)
  201                         break;
  202                 bus_space_barrier(sc->iot, sc->cfg_ioh, sc->cfgoff +
  203                     offsetof(struct ciss_config, amethod), 4,
  204                     BUS_SPACE_BARRIER_READ);
  205         }
  206 
  207         if (!(bus_space_read_4(sc->iot, sc->cfg_ioh, sc->cfgoff +
  208             offsetof(struct ciss_config, amethod)) & CISS_METH_READY)) {
  209                 printf(": she never came ready for me 0x%08x\n",
  210                     sc->cfg.amethod);
  211                 return -1;
  212         }
  213 
  214         sc->maxcmd = sc->cfg.maxcmd;
  215         sc->maxsg = sc->cfg.maxsg;
  216         if (sc->maxsg > MAXPHYS / PAGE_SIZE)
  217                 sc->maxsg = MAXPHYS / PAGE_SIZE;
  218         i = sizeof(struct ciss_ccb) +
  219             sizeof(ccb->ccb_cmd.sgl[0]) * (sc->maxsg - 1);
  220         for (sc->ccblen = 0x10; sc->ccblen < i; sc->ccblen <<= 1);
  221 
  222         total = sc->ccblen * sc->maxcmd;
  223         if ((error = bus_dmamem_alloc(sc->dmat, total, PAGE_SIZE, 0,
  224             sc->cmdseg, 1, &rseg, BUS_DMA_NOWAIT | BUS_DMA_ZERO))) {
  225                 printf(": cannot allocate CCBs (%d)\n", error);
  226                 return -1;
  227         }
  228 
  229         if ((error = bus_dmamem_map(sc->dmat, sc->cmdseg, rseg, total,
  230             (caddr_t *)&sc->ccbs, BUS_DMA_NOWAIT))) {
  231                 printf(": cannot map CCBs (%d)\n", error);
  232                 return -1;
  233         }
  234 
  235         if ((error = bus_dmamap_create(sc->dmat, total, 1,
  236             total, 0, BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, &sc->cmdmap))) {
  237                 printf(": cannot create CCBs dmamap (%d)\n", error);
  238                 bus_dmamem_free(sc->dmat, sc->cmdseg, 1);
  239                 return -1;
  240         }
  241 
  242         if ((error = bus_dmamap_load(sc->dmat, sc->cmdmap, sc->ccbs, total,
  243             NULL, BUS_DMA_NOWAIT))) {
  244                 printf(": cannot load CCBs dmamap (%d)\n", error);
  245                 bus_dmamem_free(sc->dmat, sc->cmdseg, 1);
  246                 bus_dmamap_destroy(sc->dmat, sc->cmdmap);
  247                 return -1;
  248         }
  249 
  250         SLIST_INIT(&sc->sc_free_ccb);
  251         mtx_init(&sc->sc_free_ccb_mtx, IPL_BIO);
  252 
  253         maxfer = sc->maxsg * PAGE_SIZE;
  254         for (i = 0; total; i++, total -= sc->ccblen) {
  255                 ccb = sc->ccbs + i * sc->ccblen;
  256                 cmd = &ccb->ccb_cmd;
  257                 pa = sc->cmdseg[0].ds_addr + i * sc->ccblen;
  258 
  259                 ccb->ccb_sc = sc;
  260                 ccb->ccb_cmdpa = pa + offsetof(struct ciss_ccb, ccb_cmd);
  261                 ccb->ccb_state = CISS_CCB_FREE;
  262 
  263                 cmd->id = htole32(i << 2);
  264                 cmd->id_hi = htole32(0);
  265                 cmd->sgin = sc->maxsg;
  266                 cmd->sglen = htole16((u_int16_t)cmd->sgin);
  267                 cmd->err_len = htole32(sizeof(ccb->ccb_err));
  268                 pa += offsetof(struct ciss_ccb, ccb_err);
  269                 cmd->err_pa = htole64((u_int64_t)pa);
  270 
  271                 if ((error = bus_dmamap_create(sc->dmat, maxfer, sc->maxsg,
  272                     maxfer, 0, BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW,
  273                     &ccb->ccb_dmamap)))
  274                         break;
  275 
  276                 SLIST_INSERT_HEAD(&sc->sc_free_ccb, ccb, ccb_link);
  277         }
  278 
  279         scsi_iopool_init(&sc->sc_iopool, sc, ciss_get_ccb, ciss_put_ccb);
  280 
  281         if (i < sc->maxcmd) {
  282                 printf(": cannot create ccb#%d dmamap (%d)\n", i, error);
  283                 if (i == 0) {
  284                         /* TODO leaking cmd's dmamaps and shitz */
  285                         bus_dmamem_free(sc->dmat, sc->cmdseg, 1);
  286                         bus_dmamap_destroy(sc->dmat, sc->cmdmap);
  287                         return -1;
  288                 }
  289         }
  290 
  291         if ((error = bus_dmamem_alloc(sc->dmat, PAGE_SIZE, PAGE_SIZE, 0,
  292             seg, 1, &rseg, BUS_DMA_NOWAIT | BUS_DMA_ZERO))) {
  293                 printf(": cannot allocate scratch buffer (%d)\n", error);
  294                 return -1;
  295         }
  296 
  297         if ((error = bus_dmamem_map(sc->dmat, seg, rseg, PAGE_SIZE,
  298             (caddr_t *)&sc->scratch, BUS_DMA_NOWAIT))) {
  299                 printf(": cannot map scratch buffer (%d)\n", error);
  300                 return -1;
  301         }
  302 
  303         lock = CISS_LOCK_SCRATCH(sc);
  304         inq = sc->scratch;
  305         if (ciss_inq(sc, inq)) {
  306                 printf(": adapter inquiry failed\n");
  307                 CISS_UNLOCK_SCRATCH(sc, lock);
  308                 bus_dmamem_free(sc->dmat, sc->cmdseg, 1);
  309                 bus_dmamap_destroy(sc->dmat, sc->cmdmap);
  310                 return -1;
  311         }
  312 
  313         if (!(inq->flags & CISS_INQ_BIGMAP)) {
  314                 printf(": big map is not supported, flags=%b\n",
  315                     inq->flags, CISS_INQ_BITS);
  316                 CISS_UNLOCK_SCRATCH(sc, lock);
  317                 bus_dmamem_free(sc->dmat, sc->cmdseg, 1);
  318                 bus_dmamap_destroy(sc->dmat, sc->cmdmap);
  319                 return -1;
  320         }
  321 
  322         sc->maxunits = inq->numld;
  323         sc->nbus = inq->nscsi_bus;
  324         sc->ndrives = inq->buswidth? inq->buswidth : 256;
  325         printf(": %d LD%s, HW rev %d, FW %4.4s/%4.4s",
  326             inq->numld, inq->numld == 1? "" : "s",
  327             inq->hw_rev, inq->fw_running, inq->fw_stored);
  328         if (sc->cfg.methods & CISS_METH_FIFO64)
  329                 printf(", 64bit fifo");
  330         else if (sc->cfg.methods & CISS_METH_FIFO64_RRO)
  331                 printf(", 64bit fifo rro");
  332         printf("\n");
  333 
  334         CISS_UNLOCK_SCRATCH(sc, lock);
  335 
  336         timeout_set(&sc->sc_hb, ciss_heartbeat, sc);
  337         timeout_add_sec(&sc->sc_hb, 3);
  338 
  339         /* map LDs */
  340         if (ciss_ldmap(sc)) {
  341                 printf("%s: adapter LD map failed\n", sc->sc_dev.dv_xname);
  342                 bus_dmamem_free(sc->dmat, sc->cmdseg, 1);
  343                 bus_dmamap_destroy(sc->dmat, sc->cmdmap);
  344                 return -1;
  345         }
  346 
  347         if (!(sc->sc_lds = mallocarray(sc->maxunits, sizeof(*sc->sc_lds),
  348             M_DEVBUF, M_NOWAIT | M_ZERO))) {
  349                 bus_dmamem_free(sc->dmat, sc->cmdseg, 1);
  350                 bus_dmamap_destroy(sc->dmat, sc->cmdmap);
  351                 return -1;
  352         }
  353 
  354         sc->sc_flush = CISS_FLUSH_ENABLE;
  355 
  356         saa.saa_adapter_softc = sc;
  357         saa.saa_adapter = &ciss_switch;
  358         saa.saa_luns = 1;
  359         saa.saa_adapter_target = SDEV_NO_ADAPTER_TARGET;
  360         saa.saa_adapter_buswidth = sc->maxunits;
  361         saa.saa_openings = sc->maxcmd;
  362         saa.saa_pool = &sc->sc_iopool;
  363         saa.saa_quirks = saa.saa_flags = 0;
  364         saa.saa_wwpn = saa.saa_wwnn = 0;
  365 
  366         scsibus = (struct scsibus_softc *)config_found_sm(&sc->sc_dev,
  367             &saa, scsiprint, NULL);
  368 
  369 #if NBIO > 0
  370         /* XXX for now we can only deal w/ one volume. */
  371         if (!scsibus || sc->maxunits > 1)
  372                 return 0;
  373 
  374         /* now map all the physdevs into their lds */
  375         /* XXX currently we assign all pf 'em into ld#0 */
  376         for (i = 0; i < sc->maxunits; i++)
  377                 if (!(sc->sc_lds[i] = ciss_pdscan(sc, i)))
  378                         return 0;
  379 
  380         if (bio_register(&sc->sc_dev, ciss_ioctl) != 0)
  381                 printf("%s: controller registration failed",
  382                     sc->sc_dev.dv_xname);
  383 
  384         sc->sc_flags |= CISS_BIO;
  385 #ifndef SMALL_KERNEL
  386         sc->sensors = mallocarray(sc->maxunits, sizeof(struct ksensor),
  387             M_DEVBUF, M_NOWAIT | M_ZERO);
  388         if (sc->sensors) {
  389                 struct device *dev;
  390 
  391                 strlcpy(sc->sensordev.xname, sc->sc_dev.dv_xname,
  392                     sizeof(sc->sensordev.xname));
  393                 for (i = 0; i < sc->maxunits; i++) {
  394                         sc->sensors[i].type = SENSOR_DRIVE;
  395                         sc->sensors[i].status = SENSOR_S_UNKNOWN;
  396                         dev = scsi_get_link(scsibus, i, 0)->device_softc;
  397                         strlcpy(sc->sensors[i].desc, dev->dv_xname,
  398                             sizeof(sc->sensors[i].desc));
  399                         strlcpy(sc->sc_lds[i]->xname, dev->dv_xname,
  400                             sizeof(sc->sc_lds[i]->xname));
  401                         sensor_attach(&sc->sensordev, &sc->sensors[i]);
  402                 }
  403                 if (sensor_task_register(sc, ciss_sensors, 10) == NULL)
  404                         free(sc->sensors, M_DEVBUF,
  405                             sc->maxunits * sizeof(struct ksensor));
  406                 else
  407                         sensordev_install(&sc->sensordev);
  408         }
  409 #endif /* SMALL_KERNEL */
  410 #endif /* BIO > 0 */
  411 
  412         return 0;
  413 }
  414 
  415 void
  416 ciss_shutdown(void *v)
  417 {
  418         struct ciss_softc *sc = v;
  419 
  420         sc->sc_flush = CISS_FLUSH_DISABLE;
  421         timeout_del(&sc->sc_hb);
  422         ciss_sync(sc);
  423 }
  424 
  425 /*
  426  * submit a command and optionally wait for completion.
  427  * wait arg abuses SCSI_POLL|SCSI_NOSLEEP flags to request
  428  * to wait (SCSI_POLL) and to allow tsleep() (!SCSI_NOSLEEP)
  429  * instead of busy loop waiting
  430  */
  431 int
  432 ciss_cmd(struct ciss_ccb *ccb, int flags, int wait)
  433 {
  434         struct timespec end, now, ts;
  435         struct ciss_softc *sc = ccb->ccb_sc;
  436         struct ciss_cmd *cmd = &ccb->ccb_cmd;
  437         struct ciss_ccb *ccb1;
  438         bus_dmamap_t dmap = ccb->ccb_dmamap;
  439         u_int64_t addr;
  440         uint64_t nsecs;
  441         u_int32_t id;
  442         int i, error = 0, ret;
  443 
  444         splassert(IPL_BIO);
  445 
  446         if (ccb->ccb_state != CISS_CCB_READY) {
  447                 printf("%s: ccb %d not ready state=%b\n", sc->sc_dev.dv_xname,
  448                     cmd->id, ccb->ccb_state, CISS_CCB_BITS);
  449                 return (EINVAL);
  450         }
  451 
  452         if (ccb->ccb_data) {
  453                 bus_dma_segment_t *sgd;
  454 
  455                 if ((error = bus_dmamap_load(sc->dmat, dmap, ccb->ccb_data,
  456                     ccb->ccb_len, NULL, flags))) {
  457                         if (error == EFBIG)
  458                                 printf("more than %d dma segs\n", sc->maxsg);
  459                         else
  460                                 printf("error %d loading dma map\n", error);
  461                         if (ccb->ccb_xs) {
  462                                 ccb->ccb_xs->error = XS_DRIVER_STUFFUP;
  463                                 scsi_done(ccb->ccb_xs);
  464                                 ccb->ccb_xs = NULL;
  465                         }
  466                         return (error);
  467                 }
  468                 cmd->sgin = dmap->dm_nsegs;
  469 
  470                 sgd = dmap->dm_segs;
  471                 CISS_DPRINTF(CISS_D_DMA, ("data=%p/%zu<0x%lx/%lu",
  472                     ccb->ccb_data, ccb->ccb_len, sgd->ds_addr, sgd->ds_len));
  473 
  474                 for (i = 0; i < dmap->dm_nsegs; sgd++, i++) {
  475                         cmd->sgl[i].addr_lo = htole32(sgd->ds_addr);
  476                         cmd->sgl[i].addr_hi =
  477                             htole32((u_int64_t)sgd->ds_addr >> 32);
  478                         cmd->sgl[i].len = htole32(sgd->ds_len);
  479                         cmd->sgl[i].flags = htole32(0);
  480                         if (i)
  481                                 CISS_DPRINTF(CISS_D_DMA,
  482                                     (",0x%lx/%lu", sgd->ds_addr, sgd->ds_len));
  483                 }
  484 
  485                 CISS_DPRINTF(CISS_D_DMA, ("> "));
  486 
  487                 bus_dmamap_sync(sc->dmat, dmap, 0, dmap->dm_mapsize,
  488                     BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
  489         } else
  490                 cmd->sgin = 0;
  491         cmd->sglen = htole16((u_int16_t)cmd->sgin);
  492         bzero(&ccb->ccb_err, sizeof(ccb->ccb_err));
  493 
  494         bus_dmamap_sync(sc->dmat, sc->cmdmap, 0, sc->cmdmap->dm_mapsize,
  495             BUS_DMASYNC_PREWRITE);
  496 
  497         ccb->ccb_state = CISS_CCB_ONQ;
  498         CISS_DPRINTF(CISS_D_CMD, ("submit=0x%x ", cmd->id));
  499         if (sc->cfg.methods & (CISS_METH_FIFO64|CISS_METH_FIFO64_RRO)) {
  500                 /*
  501                  * Write the upper 32bits immediately before the lower
  502                  * 32bits and set bit 63 to indicate 64bit FIFO mode.
  503                  */
  504                 addr = (u_int64_t)ccb->ccb_cmdpa;
  505                 bus_space_write_4(sc->iot, sc->ioh, CISS_INQ64_HI,
  506                     (addr >> 32) | 0x80000000);
  507                 bus_space_write_4(sc->iot, sc->ioh, CISS_INQ64_LO,
  508                     addr & 0x00000000ffffffffULL);
  509         } else
  510                 bus_space_write_4(sc->iot, sc->ioh, CISS_INQ, ccb->ccb_cmdpa);
  511 
  512         /* If we're not waiting for completion we're done. */
  513         if (!(wait & SCSI_POLL))
  514                 return (error);
  515 
  516         CISS_DPRINTF(CISS_D_CMD, ("waiting "));
  517 
  518         i = ccb->ccb_xs? ccb->ccb_xs->timeout : 60000;
  519 
  520         if (!(wait & SCSI_NOSLEEP)) {
  521                 NSEC_TO_TIMESPEC(MSEC_TO_NSEC(i), &ts);
  522                 nanouptime(&now);
  523                 timespecadd(&now, &ts, &end);
  524 
  525                 for (;;) {
  526                         ccb->ccb_state = CISS_CCB_POLL;
  527                         nsecs = TIMESPEC_TO_NSEC(&ts);
  528                         CISS_DPRINTF(CISS_D_CMD, ("tsleep_nsec(%llu) ", nsecs));
  529                         ret = tsleep_nsec(ccb, PRIBIO + 1, "ciss_cmd", nsecs);
  530                         if (ret == EWOULDBLOCK)
  531                                 break;
  532                         if (ccb->ccb_state != CISS_CCB_ONQ) {
  533                                 nanouptime(&now);
  534                                 if (timespeccmp(&end, &now, <=))
  535                                         break;
  536                                 timespecsub(&end, &now, &ts);
  537                                 CISS_DPRINTF(CISS_D_CMD, ("T"));
  538                                 continue;
  539                         }
  540                         ccb1 = ccb;
  541 
  542                         error = ciss_done(ccb1);
  543                         if (ccb1 == ccb)
  544                                 return (error);
  545                 }
  546         } else {
  547                 for (i *= 100; i--;) {
  548                         DELAY(10);
  549 
  550                         if (!(bus_space_read_4(sc->iot, sc->ioh,
  551                             CISS_ISR) & sc->iem)) {
  552                                 CISS_DPRINTF(CISS_D_CMD, ("N"));
  553                                 continue;
  554                         }
  555 
  556                         if (sc->cfg.methods & CISS_METH_FIFO64) {
  557                                 if (bus_space_read_4(sc->iot, sc->ioh,
  558                                     CISS_OUTQ64_HI) == 0xffffffff) {
  559                                         CISS_DPRINTF(CISS_D_CMD, ("Q"));
  560                                         continue;
  561                                 }
  562                                 id = bus_space_read_4(sc->iot, sc->ioh,
  563                                     CISS_OUTQ64_LO);
  564                         } else if (sc->cfg.methods &
  565                             CISS_METH_FIFO64_RRO) {
  566                                 id = bus_space_read_4(sc->iot, sc->ioh,
  567                                     CISS_OUTQ64_LO);
  568                                 if (id == 0xffffffff) {
  569                                         CISS_DPRINTF(CISS_D_CMD, ("Q"));
  570                                         continue;
  571                                 }
  572                                 (void)bus_space_read_4(sc->iot,
  573                                     sc->ioh, CISS_OUTQ64_HI);
  574                         } else {
  575                                 id = bus_space_read_4(sc->iot, sc->ioh,
  576                                     CISS_OUTQ);
  577                                 if (id == 0xffffffff) {
  578                                         CISS_DPRINTF(CISS_D_CMD, ("Q"));
  579                                         continue;
  580                                 }
  581                         }
  582 
  583                         CISS_DPRINTF(CISS_D_CMD, ("got=0x%x ", id));
  584                         ccb1 = sc->ccbs + (id >> 2) * sc->ccblen;
  585                         ccb1->ccb_cmd.id = htole32(id);
  586                         ccb1->ccb_cmd.id_hi = htole32(0);
  587 
  588                         error = ciss_done(ccb1);
  589                         if (ccb1 == ccb)
  590                                 return (error);
  591                 }
  592         }
  593 
  594         /* if never got a chance to be done above... */
  595         ccb->ccb_err.cmd_stat = CISS_ERR_TMO;
  596         error = ciss_done(ccb);
  597 
  598         CISS_DPRINTF(CISS_D_CMD, ("done %d:%d",
  599             ccb->ccb_err.cmd_stat, ccb->ccb_err.scsi_stat));
  600 
  601         return (error);
  602 }
  603 
  604 int
  605 ciss_done(struct ciss_ccb *ccb)
  606 {
  607         struct ciss_softc *sc = ccb->ccb_sc;
  608         struct scsi_xfer *xs = ccb->ccb_xs;
  609         struct ciss_cmd *cmd = &ccb->ccb_cmd;
  610         ciss_lock_t lock;
  611         int error = 0;
  612 
  613         CISS_DPRINTF(CISS_D_CMD, ("ciss_done(%p) ", ccb));
  614 
  615         if (ccb->ccb_state != CISS_CCB_ONQ) {
  616                 printf("%s: unqueued ccb %p ready, state=%b\n",
  617                     sc->sc_dev.dv_xname, ccb, ccb->ccb_state, CISS_CCB_BITS);
  618                 return 1;
  619         }
  620         lock = CISS_LOCK(sc);
  621         ccb->ccb_state = CISS_CCB_READY;
  622 
  623         if (ccb->ccb_cmd.id & CISS_CMD_ERR)
  624                 error = ciss_error(ccb);
  625 
  626         if (ccb->ccb_data) {
  627                 bus_dmamap_sync(sc->dmat, ccb->ccb_dmamap, 0,
  628                     ccb->ccb_dmamap->dm_mapsize, (cmd->flags & CISS_CDB_IN) ?
  629                     BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);
  630                 bus_dmamap_unload(sc->dmat, ccb->ccb_dmamap);
  631         }
  632 
  633         if (xs) {
  634                 xs->resid = 0;
  635                 scsi_done(xs);
  636         }
  637 
  638         CISS_UNLOCK(sc, lock);
  639 
  640         return error;
  641 }
  642 
  643 int
  644 ciss_error(struct ciss_ccb *ccb)
  645 {
  646         struct ciss_softc *sc = ccb->ccb_sc;
  647         struct ciss_error *err = &ccb->ccb_err;
  648         struct scsi_xfer *xs = ccb->ccb_xs;
  649         int rv;
  650 
  651         switch ((rv = letoh16(err->cmd_stat))) {
  652         case CISS_ERR_OK:
  653                 rv = 0;
  654                 break;
  655 
  656         case CISS_ERR_INVCMD:
  657                 printf("%s: invalid cmd 0x%x: 0x%x is not valid @ 0x%x[%d]\n",
  658                     sc->sc_dev.dv_xname, ccb->ccb_cmd.id,
  659                     err->err_info, err->err_type[3], err->err_type[2]);
  660                 if (xs) {
  661                         bzero(&xs->sense, sizeof(xs->sense));
  662                         xs->sense.error_code = SSD_ERRCODE_VALID |
  663                             SSD_ERRCODE_CURRENT;
  664                         xs->sense.flags = SKEY_ILLEGAL_REQUEST;
  665                         xs->sense.add_sense_code = 0x24; /* ill field */
  666                         xs->error = XS_SENSE;
  667                 }
  668                 rv = EIO;
  669                 break;
  670 
  671         case CISS_ERR_TMO:
  672                 xs->error = XS_TIMEOUT;
  673                 rv = ETIMEDOUT;
  674                 break;
  675 
  676         default:
  677                 if (xs) {
  678                         switch (err->scsi_stat) {
  679                         case SCSI_CHECK:
  680                                 xs->error = XS_SENSE;
  681                                 bcopy(&err->sense[0], &xs->sense,
  682                                     sizeof(xs->sense));
  683                                 rv = EIO;
  684                                 break;
  685 
  686                         case SCSI_BUSY:
  687                                 xs->error = XS_BUSY;
  688                                 rv = EBUSY;
  689                                 break;
  690 
  691                         default:
  692                                 CISS_DPRINTF(CISS_D_ERR, ("%s: "
  693                                     "cmd_stat %x scsi_stat 0x%x\n",
  694                                     sc->sc_dev.dv_xname, rv, err->scsi_stat));
  695                                 xs->error = XS_DRIVER_STUFFUP;
  696                                 rv = EIO;
  697                                 break;
  698                         }
  699                         xs->resid = letoh32(err->resid);
  700                 } else
  701                         rv = EIO;
  702         }
  703         ccb->ccb_cmd.id &= htole32(~3);
  704 
  705         return rv;
  706 }
  707 
  708 int
  709 ciss_inq(struct ciss_softc *sc, struct ciss_inquiry *inq)
  710 {
  711         struct ciss_ccb *ccb;
  712         struct ciss_cmd *cmd;
  713         int rv;
  714         int s;
  715 
  716         ccb = scsi_io_get(&sc->sc_iopool, SCSI_POLL|SCSI_NOSLEEP);
  717         if (ccb == NULL)
  718                 return ENOMEM;
  719 
  720         ccb->ccb_len = sizeof(*inq);
  721         ccb->ccb_data = inq;
  722         cmd = &ccb->ccb_cmd;
  723         cmd->tgt = htole32(CISS_CMD_MODE_PERIPH);
  724         cmd->tgt2 = 0;
  725         cmd->cdblen = 10;
  726         cmd->flags = CISS_CDB_CMD | CISS_CDB_SIMPL | CISS_CDB_IN;
  727         cmd->tmo = htole16(0);
  728         bzero(&cmd->cdb[0], sizeof(cmd->cdb));
  729         cmd->cdb[0] = CISS_CMD_CTRL_GET;
  730         cmd->cdb[6] = CISS_CMS_CTRL_CTRL;
  731         cmd->cdb[7] = sizeof(*inq) >> 8;        /* biiiig endian */
  732         cmd->cdb[8] = sizeof(*inq) & 0xff;
  733 
  734         s = splbio();
  735         rv = ciss_cmd(ccb, BUS_DMA_NOWAIT, SCSI_POLL|SCSI_NOSLEEP);
  736         splx(s);
  737 
  738         scsi_io_put(&sc->sc_iopool, ccb);
  739 
  740         return (rv);
  741 }
  742 
  743 int
  744 ciss_ldmap(struct ciss_softc *sc)
  745 {
  746         struct ciss_ccb *ccb;
  747         struct ciss_cmd *cmd;
  748         struct ciss_ldmap *lmap;
  749         ciss_lock_t lock;
  750         int total, rv;
  751 
  752         lock = CISS_LOCK_SCRATCH(sc);
  753         lmap = sc->scratch;
  754         lmap->size = htobe32(sc->maxunits * sizeof(lmap->map));
  755         total = sizeof(*lmap) + (sc->maxunits - 1) * sizeof(lmap->map);
  756 
  757         ccb = scsi_io_get(&sc->sc_iopool, SCSI_POLL|SCSI_NOSLEEP);
  758         if (ccb == NULL) {
  759                 CISS_UNLOCK_SCRATCH(sc, lock);
  760                 return ENOMEM;
  761         }
  762 
  763         ccb->ccb_len = total;
  764         ccb->ccb_data = lmap;
  765         cmd = &ccb->ccb_cmd;
  766         cmd->tgt = CISS_CMD_MODE_PERIPH;
  767         cmd->tgt2 = 0;
  768         cmd->cdblen = 12;
  769         cmd->flags = CISS_CDB_CMD | CISS_CDB_SIMPL | CISS_CDB_IN;
  770         cmd->tmo = htole16(30);
  771         bzero(&cmd->cdb[0], sizeof(cmd->cdb));
  772         cmd->cdb[0] = CISS_CMD_LDMAP;
  773         cmd->cdb[8] = total >> 8;       /* biiiig endian */
  774         cmd->cdb[9] = total & 0xff;
  775 
  776         rv = ciss_cmd(ccb, BUS_DMA_NOWAIT, SCSI_POLL|SCSI_NOSLEEP);
  777         scsi_io_put(&sc->sc_iopool, ccb);
  778         CISS_UNLOCK_SCRATCH(sc, lock);
  779 
  780         if (rv)
  781                 return rv;
  782 
  783         CISS_DPRINTF(CISS_D_MISC, ("lmap %x:%x\n",
  784             lmap->map[0].tgt, lmap->map[0].tgt2));
  785 
  786         return 0;
  787 }
  788 
  789 int
  790 ciss_sync(struct ciss_softc *sc)
  791 {
  792         struct ciss_ccb *ccb;
  793         struct ciss_cmd *cmd;
  794         struct ciss_flush *flush;
  795         ciss_lock_t lock;
  796         int rv;
  797 
  798         lock = CISS_LOCK_SCRATCH(sc);
  799         flush = sc->scratch;
  800         bzero(flush, sizeof(*flush));
  801         flush->flush = sc->sc_flush;
  802 
  803         ccb = scsi_io_get(&sc->sc_iopool, SCSI_POLL|SCSI_NOSLEEP);
  804         if (ccb == NULL) {
  805                 CISS_UNLOCK_SCRATCH(sc, lock);
  806                 return ENOMEM;
  807         }
  808 
  809         ccb->ccb_len = sizeof(*flush);
  810         ccb->ccb_data = flush;
  811         cmd = &ccb->ccb_cmd;
  812         cmd->tgt = CISS_CMD_MODE_PERIPH;
  813         cmd->tgt2 = 0;
  814         cmd->cdblen = 10;
  815         cmd->flags = CISS_CDB_CMD | CISS_CDB_SIMPL | CISS_CDB_OUT;
  816         cmd->tmo = htole16(0);
  817         bzero(&cmd->cdb[0], sizeof(cmd->cdb));
  818         cmd->cdb[0] = CISS_CMD_CTRL_SET;
  819         cmd->cdb[6] = CISS_CMS_CTRL_FLUSH;
  820         cmd->cdb[7] = sizeof(*flush) >> 8;      /* biiiig endian */
  821         cmd->cdb[8] = sizeof(*flush) & 0xff;
  822 
  823         rv = ciss_cmd(ccb, BUS_DMA_NOWAIT, SCSI_POLL|SCSI_NOSLEEP);
  824         scsi_io_put(&sc->sc_iopool, ccb);
  825         CISS_UNLOCK_SCRATCH(sc, lock);
  826 
  827         return rv;
  828 }
  829 
  830 void
  831 ciss_scsi_cmd(struct scsi_xfer *xs)
  832 {
  833         struct scsi_link *link = xs->sc_link;
  834         u_int8_t target = link->target;
  835         struct ciss_ccb *ccb;
  836         struct ciss_cmd *cmd;
  837         ciss_lock_t lock;
  838 
  839         CISS_DPRINTF(CISS_D_CMD, ("ciss_scsi_cmd "));
  840 
  841         if (xs->cmdlen > CISS_MAX_CDB) {
  842                 CISS_DPRINTF(CISS_D_CMD, ("CDB too big %p ", xs));
  843                 bzero(&xs->sense, sizeof(xs->sense));
  844                 xs->sense.error_code = SSD_ERRCODE_VALID | SSD_ERRCODE_CURRENT;
  845                 xs->sense.flags = SKEY_ILLEGAL_REQUEST;
  846                 xs->sense.add_sense_code = 0x20; /* illcmd, 0x24 illfield */
  847                 xs->error = XS_SENSE;
  848                 scsi_done(xs);
  849                 return;
  850         }
  851 
  852         xs->error = XS_NOERROR;
  853 
  854         /* XXX emulate SYNCHRONIZE_CACHE ??? */
  855 
  856         ccb = xs->io;
  857 
  858         cmd = &ccb->ccb_cmd;
  859         ccb->ccb_len = xs->datalen;
  860         ccb->ccb_data = xs->data;
  861         ccb->ccb_xs = xs;
  862         cmd->tgt = CISS_CMD_MODE_LD | target;
  863         cmd->tgt2 = 0;
  864         cmd->cdblen = xs->cmdlen;
  865         cmd->flags = CISS_CDB_CMD | CISS_CDB_SIMPL;
  866         if (xs->flags & SCSI_DATA_IN)
  867                 cmd->flags |= CISS_CDB_IN;
  868         else if (xs->flags & SCSI_DATA_OUT)
  869                 cmd->flags |= CISS_CDB_OUT;
  870         cmd->tmo = htole16(xs->timeout < 1000? 1 : xs->timeout / 1000);
  871         bzero(&cmd->cdb[0], sizeof(cmd->cdb));
  872         bcopy(&xs->cmd, &cmd->cdb[0], CISS_MAX_CDB);
  873 
  874         lock = CISS_LOCK(sc);
  875         ciss_cmd(ccb, BUS_DMA_WAITOK, xs->flags & (SCSI_POLL|SCSI_NOSLEEP));
  876         CISS_UNLOCK(sc, lock);
  877 }
  878 
  879 int
  880 ciss_intr(void *v)
  881 {
  882         struct ciss_softc *sc = v;
  883         struct ciss_ccb *ccb;
  884         bus_size_t reg;
  885         u_int32_t id;
  886         int hit = 0;
  887 
  888         CISS_DPRINTF(CISS_D_INTR, ("intr "));
  889 
  890         if (!(bus_space_read_4(sc->iot, sc->ioh, CISS_ISR) & sc->iem))
  891                 return 0;
  892 
  893         if (sc->cfg.methods & CISS_METH_FIFO64)
  894                 reg = CISS_OUTQ64_HI;
  895         else if (sc->cfg.methods & CISS_METH_FIFO64_RRO)
  896                 reg = CISS_OUTQ64_LO;
  897         else
  898                 reg = CISS_OUTQ;
  899         while ((id = bus_space_read_4(sc->iot, sc->ioh, reg)) != 0xffffffff) {
  900                 if (reg == CISS_OUTQ64_HI)
  901                         id = bus_space_read_4(sc->iot, sc->ioh,
  902                             CISS_OUTQ64_LO);
  903                 else if (reg == CISS_OUTQ64_LO)
  904                         (void)bus_space_read_4(sc->iot, sc->ioh,
  905                             CISS_OUTQ64_HI);
  906                 ccb = sc->ccbs + (id >> 2) * sc->ccblen;
  907                 ccb->ccb_cmd.id = htole32(id);
  908                 ccb->ccb_cmd.id_hi = htole32(0); /* ignore the upper 32bits */
  909                 if (ccb->ccb_state == CISS_CCB_POLL) {
  910                         ccb->ccb_state = CISS_CCB_ONQ;
  911                         wakeup(ccb);
  912                 } else
  913                         ciss_done(ccb);
  914 
  915                 hit = 1;
  916         }
  917         CISS_DPRINTF(CISS_D_INTR, ("exit "));
  918         return hit;
  919 }
  920 
  921 void
  922 ciss_heartbeat(void *v)
  923 {
  924         struct ciss_softc *sc = v;
  925         u_int32_t hb;
  926 
  927         hb = bus_space_read_4(sc->iot, sc->cfg_ioh,
  928             sc->cfgoff + offsetof(struct ciss_config, heartbeat));
  929         if (hb == sc->heartbeat) {
  930                 sc->fibrillation++;
  931                 CISS_DPRINTF(CISS_D_ERR, ("%s: fibrillation #%d (value=%d)\n",
  932                     sc->sc_dev.dv_xname, sc->fibrillation, hb));
  933                 if (sc->fibrillation >= 11) {
  934                         /* No heartbeat for 33 seconds */
  935                         panic("%s: dead", sc->sc_dev.dv_xname); /* XXX reset! */
  936                 }
  937         } else {
  938                 sc->heartbeat = hb;
  939                 if (sc->fibrillation) {
  940                         CISS_DPRINTF(CISS_D_ERR, ("%s: "
  941                             "fibrillation ended (value=%d)\n",
  942                             sc->sc_dev.dv_xname, hb));
  943                 }
  944                 sc->fibrillation = 0;
  945         }
  946 
  947         timeout_add_sec(&sc->sc_hb, 3);
  948 }
  949 
  950 int
  951 ciss_scsi_ioctl(struct scsi_link *link, u_long cmd, caddr_t addr, int flag)
  952 {
  953 #if NBIO > 0
  954         return ciss_ioctl(link->bus->sb_adapter_softc, cmd, addr);
  955 #else
  956         return ENOTTY;
  957 #endif
  958 }
  959 
  960 #if NBIO > 0
  961 const int ciss_level[] = { 0, 4, 1, 5, 51, 7 };
  962 const int ciss_stat[] = { BIOC_SVONLINE, BIOC_SVOFFLINE, BIOC_SVOFFLINE,
  963     BIOC_SVDEGRADED, BIOC_SVREBUILD, BIOC_SVREBUILD, BIOC_SVDEGRADED,
  964     BIOC_SVDEGRADED, BIOC_SVINVALID, BIOC_SVINVALID, BIOC_SVBUILDING,
  965     BIOC_SVOFFLINE, BIOC_SVBUILDING };
  966 
  967 int
  968 ciss_ioctl(struct device *dev, u_long cmd, caddr_t addr)
  969 {
  970         struct ciss_softc *sc = (struct ciss_softc *)dev;
  971         struct bioc_inq *bi;
  972         struct bioc_vol *bv;
  973         struct bioc_disk *bd;
  974         struct bioc_blink *bb;
  975         /* struct bioc_alarm *ba; */
  976         /* struct bioc_setstate *bss; */
  977         struct ciss_ldid *ldid;
  978         struct ciss_ldstat *ldstat;
  979         struct ciss_pdid *pdid;
  980         struct ciss_blink *blink;
  981         struct ciss_ld *ldp;
  982         ciss_lock_t lock;
  983         u_int8_t drv;
  984         int ld, pd, error = 0;
  985         u_int blks;
  986 
  987         if (!(sc->sc_flags & CISS_BIO))
  988                 return ENOTTY;
  989 
  990         lock = CISS_LOCK(sc);
  991         switch (cmd) {
  992         case BIOCINQ:
  993                 bi = (struct bioc_inq *)addr;
  994                 strlcpy(bi->bi_dev, sc->sc_dev.dv_xname, sizeof(bi->bi_dev));
  995                 bi->bi_novol = sc->maxunits;
  996                 bi->bi_nodisk = sc->ndrives;
  997                 break;
  998 
  999         case BIOCVOL:
 1000                 bv = (struct bioc_vol *)addr;
 1001                 if (bv->bv_volid > sc->maxunits) {
 1002                         error = EINVAL;
 1003                         break;
 1004                 }
 1005                 ldp = sc->sc_lds[bv->bv_volid];
 1006                 if (!ldp) {
 1007                         error = EINVAL;
 1008                         break;
 1009                 }
 1010                 ldid = sc->scratch;
 1011                 if ((error = ciss_ldid(sc, bv->bv_volid, ldid)))
 1012                         break;
 1013                 /* params 30:88:ff:00:00:00:00:00:00:00:00:00:00:00:20:00 */
 1014                 bv->bv_status = BIOC_SVINVALID;
 1015                 blks = (u_int)letoh16(ldid->nblocks[1]) << 16 |
 1016                     letoh16(ldid->nblocks[0]);
 1017                 bv->bv_size = blks * (uint64_t)letoh16(ldid->blksize);
 1018                 bv->bv_level = ciss_level[ldid->type];
 1019                 bv->bv_nodisk = ldp->ndrives;
 1020                 strlcpy(bv->bv_dev, ldp->xname, sizeof(bv->bv_dev));
 1021                 strlcpy(bv->bv_vendor, "CISS", sizeof(bv->bv_vendor));
 1022                 ldstat = sc->scratch;
 1023                 bzero(ldstat, sizeof(*ldstat));
 1024                 if ((error = ciss_ldstat(sc, bv->bv_volid, ldstat)))
 1025                         break;
 1026                 bv->bv_percent = -1;
 1027                 bv->bv_seconds = 0;
 1028                 if (ldstat->stat < nitems(ciss_stat))
 1029                         bv->bv_status = ciss_stat[ldstat->stat];
 1030                 if (bv->bv_status == BIOC_SVREBUILD ||
 1031                     bv->bv_status == BIOC_SVBUILDING)
 1032                         bv->bv_percent = (blks -
 1033                             (((u_int)ldstat->prog[3] << 24) |
 1034                             ((u_int)ldstat->prog[2] << 16) |
 1035                             ((u_int)ldstat->prog[1] << 8) |
 1036                             (u_int)ldstat->prog[0])) * 100ULL / blks;
 1037                 break;
 1038 
 1039         case BIOCDISK:
 1040                 bd = (struct bioc_disk *)addr;
 1041                 if (bd->bd_volid > sc->maxunits) {
 1042                         error = EINVAL;
 1043                         break;
 1044                 }
 1045                 ldp = sc->sc_lds[bd->bd_volid];
 1046                 if (!ldp || (pd = bd->bd_diskid) > ldp->ndrives) {
 1047                         error = EINVAL;
 1048                         break;
 1049                 }
 1050                 ldstat = sc->scratch;
 1051                 if ((error = ciss_ldstat(sc, bd->bd_volid, ldstat)))
 1052                         break;
 1053                 bd->bd_status = -1;
 1054                 if (ldstat->stat == CISS_LD_REBLD &&
 1055                     ldstat->bigrebuild == ldp->tgts[pd])
 1056                         bd->bd_status = BIOC_SDREBUILD;
 1057                 if (ciss_bitset(ldp->tgts[pd] & (~CISS_BIGBIT),
 1058                     ldstat->bigfailed)) {
 1059                         bd->bd_status = BIOC_SDFAILED;
 1060                         bd->bd_size = 0;
 1061                         bd->bd_channel = (ldp->tgts[pd] & (~CISS_BIGBIT)) /
 1062                             sc->ndrives;
 1063                         bd->bd_target = ldp->tgts[pd] % sc->ndrives;
 1064                         bd->bd_lun = 0;
 1065                         bd->bd_vendor[0] = '\0';
 1066                         bd->bd_serial[0] = '\0';
 1067                         bd->bd_procdev[0] = '\0';
 1068                 } else {
 1069                         pdid = sc->scratch;
 1070                         if ((error = ciss_pdid(sc, ldp->tgts[pd], pdid,
 1071                             SCSI_POLL)))
 1072                                 break;
 1073                         if (bd->bd_status < 0) {
 1074                                 if (pdid->config & CISS_PD_SPARE)
 1075                                         bd->bd_status = BIOC_SDHOTSPARE;
 1076                                 else if (pdid->present & CISS_PD_PRESENT)
 1077                                         bd->bd_status = BIOC_SDONLINE;
 1078                                 else
 1079                                         bd->bd_status = BIOC_SDINVALID;
 1080                         }
 1081                         bd->bd_size = (u_int64_t)letoh32(pdid->nblocks) *
 1082                             letoh16(pdid->blksz);
 1083                         bd->bd_channel = pdid->bus;
 1084                         bd->bd_target = pdid->target;
 1085                         bd->bd_lun = 0;
 1086                         strlcpy(bd->bd_vendor, pdid->model,
 1087                             sizeof(bd->bd_vendor));
 1088                         strlcpy(bd->bd_serial, pdid->serial,
 1089                             sizeof(bd->bd_serial));
 1090                         bd->bd_procdev[0] = '\0';
 1091                 }
 1092                 break;
 1093 
 1094         case BIOCBLINK:
 1095                 bb = (struct bioc_blink *)addr;
 1096                 blink = sc->scratch;
 1097                 error = EINVAL;
 1098                 /* XXX workaround completely dumb scsi addressing */
 1099                 for (ld = 0; ld < sc->maxunits; ld++) {
 1100                         ldp = sc->sc_lds[ld];
 1101                         if (!ldp)
 1102                                 continue;
 1103                         if (sc->ndrives == 256)
 1104                                 drv = bb->bb_target;
 1105                         else
 1106                                 drv = CISS_BIGBIT +
 1107                                     bb->bb_channel * sc->ndrives +
 1108                                     bb->bb_target;
 1109                         for (pd = 0; pd < ldp->ndrives; pd++)
 1110                                 if (ldp->tgts[pd] == drv)
 1111                                         error = ciss_blink(sc, ld, pd,
 1112                                             bb->bb_status, blink);
 1113                 }
 1114                 break;
 1115 
 1116         case BIOCALARM:
 1117         case BIOCSETSTATE:
 1118         default:
 1119                 CISS_DPRINTF(CISS_D_IOCTL, ("%s: invalid ioctl\n",
 1120                     sc->sc_dev.dv_xname));
 1121                 error = ENOTTY;
 1122         }
 1123         CISS_UNLOCK(sc, lock);
 1124 
 1125         return error;
 1126 }
 1127 
 1128 #ifndef SMALL_KERNEL
 1129 void
 1130 ciss_sensors(void *v)
 1131 {
 1132         struct ciss_softc *sc = v;
 1133         struct ciss_ldstat *ldstat;
 1134         int i, error;
 1135 
 1136         for (i = 0; i < sc->maxunits; i++) {
 1137                 ldstat = sc->scratch;
 1138                 if ((error = ciss_ldstat(sc, i, ldstat))) {
 1139                         sc->sensors[i].value = 0;
 1140                         sc->sensors[i].status = SENSOR_S_UNKNOWN;
 1141                         continue;
 1142                 }
 1143 
 1144                 switch (ldstat->stat) {
 1145                 case CISS_LD_OK:
 1146                         sc->sensors[i].value = SENSOR_DRIVE_ONLINE;
 1147                         sc->sensors[i].status = SENSOR_S_OK;
 1148                         break;
 1149 
 1150                 case CISS_LD_DEGRAD:
 1151                         sc->sensors[i].value = SENSOR_DRIVE_PFAIL;
 1152                         sc->sensors[i].status = SENSOR_S_WARN;
 1153                         break;
 1154 
 1155                 case CISS_LD_EXPND:
 1156                 case CISS_LD_QEXPND:
 1157                 case CISS_LD_RBLDRD:
 1158                 case CISS_LD_REBLD:
 1159                         sc->sensors[i].value = SENSOR_DRIVE_REBUILD;
 1160                         sc->sensors[i].status = SENSOR_S_WARN;
 1161                         break;
 1162 
 1163                 case CISS_LD_NORDY:
 1164                 case CISS_LD_PDINV:
 1165                 case CISS_LD_PDUNC:
 1166                 case CISS_LD_FAILED:
 1167                 case CISS_LD_UNCONF:
 1168                         sc->sensors[i].value = SENSOR_DRIVE_FAIL;
 1169                         sc->sensors[i].status = SENSOR_S_CRIT;
 1170                         break;
 1171 
 1172                 default:
 1173                         sc->sensors[i].value = 0;
 1174                         sc->sensors[i].status = SENSOR_S_UNKNOWN;
 1175                 }
 1176         }
 1177 }
 1178 #endif /* SMALL_KERNEL */
 1179 
 1180 int
 1181 ciss_ldid(struct ciss_softc *sc, int target, struct ciss_ldid *id)
 1182 {
 1183         struct ciss_ccb *ccb;
 1184         struct ciss_cmd *cmd;
 1185         int rv;
 1186         int s;
 1187 
 1188         ccb = scsi_io_get(&sc->sc_iopool, SCSI_POLL);
 1189         if (ccb == NULL)
 1190                 return ENOMEM;
 1191 
 1192         ccb->ccb_len = sizeof(*id);
 1193         ccb->ccb_data = id;
 1194         cmd = &ccb->ccb_cmd;
 1195         cmd->tgt = htole32(CISS_CMD_MODE_PERIPH);
 1196         cmd->tgt2 = 0;
 1197         cmd->cdblen = 10;
 1198         cmd->flags = CISS_CDB_CMD | CISS_CDB_SIMPL | CISS_CDB_IN;
 1199         cmd->tmo = htole16(0);
 1200         bzero(&cmd->cdb[0], sizeof(cmd->cdb));
 1201         cmd->cdb[0] = CISS_CMD_CTRL_GET;
 1202         cmd->cdb[5] = target;
 1203         cmd->cdb[6] = CISS_CMS_CTRL_LDIDEXT;
 1204         cmd->cdb[7] = sizeof(*id) >> 8; /* biiiig endian */
 1205         cmd->cdb[8] = sizeof(*id) & 0xff;
 1206 
 1207         s = splbio();
 1208         rv = ciss_cmd(ccb, BUS_DMA_NOWAIT, SCSI_POLL);
 1209         splx(s);
 1210 
 1211         scsi_io_put(&sc->sc_iopool, ccb);
 1212 
 1213         return (rv);
 1214 }
 1215 
 1216 int
 1217 ciss_ldstat(struct ciss_softc *sc, int target, struct ciss_ldstat *stat)
 1218 {
 1219         struct ciss_ccb *ccb;
 1220         struct ciss_cmd *cmd;
 1221         int rv;
 1222         int s;
 1223 
 1224         ccb = scsi_io_get(&sc->sc_iopool, SCSI_POLL);
 1225         if (ccb == NULL)
 1226                 return ENOMEM;
 1227 
 1228         ccb->ccb_len = sizeof(*stat);
 1229         ccb->ccb_data = stat;
 1230         cmd = &ccb->ccb_cmd;
 1231         cmd->tgt = htole32(CISS_CMD_MODE_PERIPH);
 1232         cmd->tgt2 = 0;
 1233         cmd->cdblen = 10;
 1234         cmd->flags = CISS_CDB_CMD | CISS_CDB_SIMPL | CISS_CDB_IN;
 1235         cmd->tmo = htole16(0);
 1236         bzero(&cmd->cdb[0], sizeof(cmd->cdb));
 1237         cmd->cdb[0] = CISS_CMD_CTRL_GET;
 1238         cmd->cdb[5] = target;
 1239         cmd->cdb[6] = CISS_CMS_CTRL_LDSTAT;
 1240         cmd->cdb[7] = sizeof(*stat) >> 8;       /* biiiig endian */
 1241         cmd->cdb[8] = sizeof(*stat) & 0xff;
 1242 
 1243         s = splbio();
 1244         rv = ciss_cmd(ccb, BUS_DMA_NOWAIT, SCSI_POLL);
 1245         splx(s);
 1246 
 1247         scsi_io_put(&sc->sc_iopool, ccb);
 1248 
 1249         return (rv);
 1250 }
 1251 
 1252 int
 1253 ciss_pdid(struct ciss_softc *sc, u_int8_t drv, struct ciss_pdid *id, int wait)
 1254 {
 1255         struct ciss_ccb *ccb;
 1256         struct ciss_cmd *cmd;
 1257         int rv;
 1258         int s;
 1259 
 1260         ccb = scsi_io_get(&sc->sc_iopool, SCSI_POLL);
 1261         if (ccb == NULL)
 1262                 return ENOMEM;
 1263 
 1264         ccb->ccb_len = sizeof(*id);
 1265         ccb->ccb_data = id;
 1266         cmd = &ccb->ccb_cmd;
 1267         cmd->tgt = htole32(CISS_CMD_MODE_PERIPH);
 1268         cmd->tgt2 = 0;
 1269         cmd->cdblen = 10;
 1270         cmd->flags = CISS_CDB_CMD | CISS_CDB_SIMPL | CISS_CDB_IN;
 1271         cmd->tmo = htole16(0);
 1272         bzero(&cmd->cdb[0], sizeof(cmd->cdb));
 1273         cmd->cdb[0] = CISS_CMD_CTRL_GET;
 1274         cmd->cdb[2] = drv;
 1275         cmd->cdb[6] = CISS_CMS_CTRL_PDID;
 1276         cmd->cdb[7] = sizeof(*id) >> 8; /* biiiig endian */
 1277         cmd->cdb[8] = sizeof(*id) & 0xff;
 1278 
 1279         s = splbio();
 1280         rv = ciss_cmd(ccb, BUS_DMA_NOWAIT, wait);
 1281         splx(s);
 1282 
 1283         scsi_io_put(&sc->sc_iopool, ccb);
 1284 
 1285         return (rv);
 1286 }
 1287 
 1288 
 1289 struct ciss_ld *
 1290 ciss_pdscan(struct ciss_softc *sc, int ld)
 1291 {
 1292         struct ciss_pdid *pdid;
 1293         struct ciss_ld *ldp;
 1294         u_int8_t drv, buf[128];
 1295         int i, j, k = 0;
 1296 
 1297         pdid = sc->scratch;
 1298         if (sc->ndrives == 256) {
 1299                 for (i = 0; i < CISS_BIGBIT; i++)
 1300                         if (!ciss_pdid(sc, i, pdid, SCSI_NOSLEEP|SCSI_POLL) &&
 1301                             (pdid->present & CISS_PD_PRESENT))
 1302                                 buf[k++] = i;
 1303         } else
 1304                 for (i = 0; i < sc->nbus; i++)
 1305                         for (j = 0; j < sc->ndrives; j++) {
 1306                                 drv = CISS_BIGBIT + i * sc->ndrives + j;
 1307                                 if (!ciss_pdid(sc, drv, pdid,
 1308                                     SCSI_NOSLEEP|SCSI_POLL))
 1309                                         buf[k++] = drv;
 1310                         }
 1311 
 1312         if (!k)
 1313                 return NULL;
 1314 
 1315         ldp = malloc(sizeof(*ldp) + (k-1), M_DEVBUF, M_NOWAIT);
 1316         if (!ldp)
 1317                 return NULL;
 1318 
 1319         bzero(&ldp->bling, sizeof(ldp->bling));
 1320         ldp->ndrives = k;
 1321         bcopy(buf, ldp->tgts, k);
 1322         return ldp;
 1323 }
 1324 
 1325 int
 1326 ciss_blink(struct ciss_softc *sc, int ld, int pd, int stat,
 1327     struct ciss_blink *blink)
 1328 {
 1329         struct ciss_ccb *ccb;
 1330         struct ciss_cmd *cmd;
 1331         struct ciss_ld *ldp;
 1332         int rv;
 1333         int s;
 1334 
 1335         if (ld > sc->maxunits)
 1336                 return EINVAL;
 1337 
 1338         ldp = sc->sc_lds[ld];
 1339         if (!ldp || pd > ldp->ndrives)
 1340                 return EINVAL;
 1341 
 1342         ldp->bling.pdtab[ldp->tgts[pd]] = stat == BIOC_SBUNBLINK? 0 :
 1343             CISS_BLINK_ALL;
 1344         bcopy(&ldp->bling, blink, sizeof(*blink));
 1345 
 1346         ccb = scsi_io_get(&sc->sc_iopool, SCSI_POLL);
 1347         if (ccb == NULL)
 1348                 return ENOMEM;
 1349 
 1350         ccb->ccb_len = sizeof(*blink);
 1351         ccb->ccb_data = blink;
 1352         cmd = &ccb->ccb_cmd;
 1353         cmd->tgt = htole32(CISS_CMD_MODE_PERIPH);
 1354         cmd->tgt2 = 0;
 1355         cmd->cdblen = 10;
 1356         cmd->flags = CISS_CDB_CMD | CISS_CDB_SIMPL | CISS_CDB_OUT;
 1357         cmd->tmo = htole16(0);
 1358         bzero(&cmd->cdb[0], sizeof(cmd->cdb));
 1359         cmd->cdb[0] = CISS_CMD_CTRL_SET;
 1360         cmd->cdb[6] = CISS_CMS_CTRL_PDBLINK;
 1361         cmd->cdb[7] = sizeof(*blink) >> 8;      /* biiiig endian */
 1362         cmd->cdb[8] = sizeof(*blink) & 0xff;
 1363 
 1364         s = splbio();
 1365         rv = ciss_cmd(ccb, BUS_DMA_NOWAIT, SCSI_POLL);
 1366         splx(s);
 1367 
 1368         scsi_io_put(&sc->sc_iopool, ccb);
 1369 
 1370         return (rv);
 1371 }
 1372 #endif

Cache object: c7f3bbe100f5c8fb2f65d657679084b6


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