root/dev/ic/cac.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. cac_init
  2. cac_flush
  3. cac_shutdown
  4. cac_intr
  5. cac_cmd
  6. cac_ccb_poll
  7. cac_ccb_start
  8. cac_ccb_done
  9. cac_ccb_alloc
  10. cac_ccb_free
  11. cac_get_dinfo
  12. cacminphys
  13. cac_copy_internal_data
  14. cac_scsi_cmd
  15. cac_l0_fifo_full
  16. cac_l0_submit
  17. cac_l0_completed
  18. cac_l0_intr_pending
  19. cac_l0_intr_enable

    1 /*      $OpenBSD: cac.c,v 1.23 2006/11/28 23:59:45 dlg 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  * 3. All advertising materials mentioning features or use of this software
   48  *    must display the following acknowledgement:
   49  *        This product includes software developed by the NetBSD
   50  *        Foundation, Inc. and its contributors.
   51  * 4. Neither the name of The NetBSD Foundation nor the names of its
   52  *    contributors may be used to endorse or promote products derived
   53  *    from this software without specific prior written permission.
   54  *
   55  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
   56  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   57  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   58  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
   59  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   60  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   61  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   62  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   63  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   64  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   65  * POSSIBILITY OF SUCH DAMAGE.
   66  */
   67 
   68 /*
   69  * Driver for Compaq array controllers.
   70  */
   71 
   72 /* #define      CAC_DEBUG */
   73 
   74 #include <sys/param.h>
   75 #include <sys/systm.h>
   76 #include <sys/kernel.h>
   77 #include <sys/device.h>
   78 #include <sys/queue.h>
   79 #include <sys/proc.h>
   80 #include <sys/buf.h>
   81 #include <sys/endian.h>
   82 #include <sys/malloc.h>
   83 #include <sys/pool.h>
   84 
   85 #include <machine/bus.h>
   86 
   87 #include <scsi/scsi_all.h>
   88 #include <scsi/scsi_disk.h>
   89 #include <scsi/scsiconf.h>
   90 
   91 #include <dev/ic/cacreg.h>
   92 #include <dev/ic/cacvar.h>
   93 
   94 struct cfdriver cac_cd = {
   95         NULL, "cac", DV_DULL
   96 };
   97 
   98 int     cac_scsi_cmd(struct scsi_xfer *);
   99 void    cacminphys(struct buf *bp);
  100 
  101 struct scsi_adapter cac_switch = {
  102         cac_scsi_cmd, cacminphys, 0, 0,
  103 };
  104 
  105 struct scsi_device cac_dev = {
  106         NULL, NULL, NULL, NULL
  107 };
  108 
  109 struct  cac_ccb *cac_ccb_alloc(struct cac_softc *, int);
  110 void    cac_ccb_done(struct cac_softc *, struct cac_ccb *);
  111 void    cac_ccb_free(struct cac_softc *, struct cac_ccb *);
  112 int     cac_ccb_poll(struct cac_softc *, struct cac_ccb *, int);
  113 int     cac_ccb_start(struct cac_softc *, struct cac_ccb *);
  114 int     cac_cmd(struct cac_softc *sc, int command, void *data, int datasize,
  115         int drive, int blkno, int flags, struct scsi_xfer *xs);
  116 int     cac_get_dinfo(struct cac_softc *sc, int target);
  117 int     cac_flush(struct cac_softc *sc);
  118 void    cac_shutdown(void *);
  119 void    cac_copy_internal_data(struct scsi_xfer *xs, void *v, size_t size);
  120 
  121 struct  cac_ccb *cac_l0_completed(struct cac_softc *);
  122 int     cac_l0_fifo_full(struct cac_softc *);
  123 void    cac_l0_intr_enable(struct cac_softc *, int);
  124 int     cac_l0_intr_pending(struct cac_softc *);
  125 void    cac_l0_submit(struct cac_softc *, struct cac_ccb *);
  126 
  127 void    *cac_sdh;       /* shutdown hook */
  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 
  153         size = sizeof(struct cac_ccb) * CAC_MAX_CCBS;
  154 
  155         if ((error = bus_dmamem_alloc(sc->sc_dmat, size, PAGE_SIZE, 0, seg, 1,
  156             &rseg, BUS_DMA_NOWAIT)) != 0) {
  157                 printf("%s: unable to allocate CCBs, error = %d\n",
  158                     sc->sc_dv.dv_xname, error);
  159                 return (-1);
  160         }
  161 
  162         if ((error = bus_dmamem_map(sc->sc_dmat, seg, rseg, size,
  163             &sc->sc_ccbs, BUS_DMA_NOWAIT | BUS_DMA_COHERENT)) != 0) {
  164                 printf("%s: unable to map CCBs, error = %d\n",
  165                     sc->sc_dv.dv_xname, error);
  166                 return (-1);
  167         }
  168 
  169         if ((error = bus_dmamap_create(sc->sc_dmat, size, 1, size, 0,
  170             BUS_DMA_NOWAIT, &sc->sc_dmamap)) != 0) {
  171                 printf("%s: unable to create CCB DMA map, error = %d\n",
  172                     sc->sc_dv.dv_xname, error);
  173                 return (-1);
  174         }
  175 
  176         if ((error = bus_dmamap_load(sc->sc_dmat, sc->sc_dmamap, sc->sc_ccbs,
  177             size, NULL, BUS_DMA_NOWAIT)) != 0) {
  178                 printf("%s: unable to load CCB DMA map, error = %d\n",
  179                     sc->sc_dv.dv_xname, error);
  180                 return (-1);
  181         }
  182 
  183         sc->sc_ccbs_paddr = sc->sc_dmamap->dm_segs[0].ds_addr;
  184         memset(sc->sc_ccbs, 0, size);
  185         ccb = (struct cac_ccb *)sc->sc_ccbs;
  186 
  187         for (i = 0; i < CAC_MAX_CCBS; i++, ccb++) {
  188                 /* Create the DMA map for this CCB's data */
  189                 error = bus_dmamap_create(sc->sc_dmat, CAC_MAX_XFER,
  190                     CAC_SG_SIZE, CAC_MAX_XFER, 0,
  191                     BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW,
  192                     &ccb->ccb_dmamap_xfer);
  193 
  194                 if (error) {
  195                         printf("%s: can't create ccb dmamap (%d)\n",
  196                             sc->sc_dv.dv_xname, error);
  197                         break;
  198                 }
  199 
  200                 ccb->ccb_paddr = sc->sc_ccbs_paddr + i * sizeof(struct cac_ccb);
  201                 SIMPLEQ_INSERT_TAIL(&sc->sc_ccb_free, ccb, ccb_chain);
  202         }
  203 
  204         /* Start firmware background tasks, if needed. */
  205         if (startfw) {
  206                 if (cac_cmd(sc, CAC_CMD_START_FIRMWARE, &cinfo, sizeof(cinfo),
  207                     0, 0, CAC_CCB_DATA_IN, NULL)) {
  208                         printf("%s: CAC_CMD_START_FIRMWARE failed\n",
  209                             sc->sc_dv.dv_xname);
  210                         return (-1);
  211                 }
  212         }
  213 
  214         if (cac_cmd(sc, CAC_CMD_GET_CTRL_INFO, &cinfo, sizeof(cinfo), 0, 0,
  215             CAC_CCB_DATA_IN, NULL)) {
  216                 printf("%s: CAC_CMD_GET_CTRL_INFO failed\n",
  217                     sc->sc_dv.dv_xname);
  218                 return (-1);
  219         }
  220 
  221         if (!cinfo.num_drvs) {
  222                 printf("%s: no volumes defined\n", sc->sc_dv.dv_xname);
  223                 return (-1);
  224         }
  225 
  226         sc->sc_nunits = cinfo.num_drvs;
  227         sc->sc_dinfos = malloc(cinfo.num_drvs * sizeof(struct cac_drive_info),
  228             M_DEVBUF, M_NOWAIT);
  229         if (sc->sc_dinfos == NULL) {
  230                 printf("%s: cannot allocate memory for drive_info\n",
  231                     sc->sc_dv.dv_xname);
  232                 return (-1);
  233         }
  234         bzero(sc->sc_dinfos, cinfo.num_drvs * sizeof(struct cac_drive_info));
  235 
  236         sc->sc_link.adapter_softc = sc;
  237         sc->sc_link.adapter = &cac_switch;
  238         sc->sc_link.adapter_target = cinfo.num_drvs;
  239         sc->sc_link.adapter_buswidth = cinfo.num_drvs;
  240         sc->sc_link.device = &cac_dev;
  241         sc->sc_link.openings = CAC_MAX_CCBS / sc->sc_nunits;
  242         if (sc->sc_link.openings < 4 )
  243                 sc->sc_link.openings = 4;
  244 
  245         bzero(&saa, sizeof(saa));
  246         saa.saa_sc_link = &sc->sc_link;
  247 
  248         config_found(&sc->sc_dv, &saa, scsiprint);
  249 
  250         /* Set our `shutdownhook' before we start any device activity. */
  251         if (cac_sdh == NULL)
  252                 cac_sdh = shutdownhook_establish(cac_shutdown, NULL);
  253 
  254         (*sc->sc_cl->cl_intr_enable)(sc, 1);
  255 
  256         return (0);
  257 }
  258 
  259 int
  260 cac_flush(sc)
  261         struct cac_softc *sc;
  262 {
  263         u_int8_t buf[512];
  264 
  265         memset(buf, 0, sizeof(buf));
  266         buf[0] = 1;
  267         return cac_cmd(sc, CAC_CMD_FLUSH_CACHE, buf, sizeof(buf), 0, 0,
  268             CAC_CCB_DATA_OUT, NULL);
  269 }
  270 
  271 /*
  272  * Shut down all `cac' controllers.
  273  */
  274 void
  275 cac_shutdown(void *cookie)
  276 {
  277         extern struct cfdriver cac_cd;
  278         struct cac_softc *sc;
  279         int i;
  280 
  281         for (i = 0; i < cac_cd.cd_ndevs; i++) {
  282                 if ((sc = (struct cac_softc *)device_lookup(&cac_cd, i)) == NULL)
  283                         continue;
  284                 cac_flush(sc);
  285         }
  286 }
  287 
  288 /*
  289  * Handle an interrupt from the controller: process finished CCBs and
  290  * dequeue any waiting CCBs.
  291  */
  292 int
  293 cac_intr(v)
  294         void *v;
  295 {
  296         struct cac_softc *sc = v;
  297         struct cac_ccb *ccb;
  298         int istat, ret = 0;
  299 
  300         if (!(istat = (sc->sc_cl->cl_intr_pending)(sc)))
  301                 return 0;
  302 
  303         if (istat & CAC_INTR_FIFO_NEMPTY)
  304                 while ((ccb = (*sc->sc_cl->cl_completed)(sc)) != NULL) {
  305                         ret = 1;
  306                         cac_ccb_done(sc, ccb);
  307                 }
  308         cac_ccb_start(sc, NULL);
  309 
  310         return (ret);
  311 }
  312 
  313 /*
  314  * Execute a [polled] command.
  315  */
  316 int
  317 cac_cmd(struct cac_softc *sc, int command, void *data, int datasize,
  318         int drive, int blkno, int flags, struct scsi_xfer *xs)
  319 {
  320         struct cac_ccb *ccb;
  321         struct cac_sgb *sgb;
  322         int i, rv, size, nsegs;
  323 
  324 #ifdef CAC_DEBUG
  325         printf("cac_cmd op=%x drv=%d blk=%d data=%p[%x] fl=%x xs=%p ",
  326             command, drive, blkno, data, datasize, flags, xs);
  327 #endif
  328 
  329         if ((ccb = cac_ccb_alloc(sc, 0)) == NULL) {
  330                 printf("%s: unable to alloc CCB\n", sc->sc_dv.dv_xname);
  331                 return (ENOMEM);
  332         }
  333 
  334         if ((flags & (CAC_CCB_DATA_IN | CAC_CCB_DATA_OUT)) != 0) {
  335                 bus_dmamap_load(sc->sc_dmat, ccb->ccb_dmamap_xfer,
  336                     (void *)data, datasize, NULL, BUS_DMA_NOWAIT);
  337 
  338                 bus_dmamap_sync(sc->sc_dmat, ccb->ccb_dmamap_xfer, 0,
  339                     ccb->ccb_dmamap_xfer->dm_mapsize,
  340                     (flags & CAC_CCB_DATA_IN) != 0 ? BUS_DMASYNC_PREREAD :
  341                     BUS_DMASYNC_PREWRITE);
  342 
  343                 sgb = ccb->ccb_seg;
  344                 nsegs = ccb->ccb_dmamap_xfer->dm_nsegs;
  345                 if (nsegs > CAC_SG_SIZE)
  346                         panic("cac_cmd: nsegs botch");
  347 
  348                 size = 0;
  349                 for (i = 0; i < nsegs; i++, sgb++) {
  350                         size += ccb->ccb_dmamap_xfer->dm_segs[i].ds_len;
  351                         sgb->length =
  352                             htole32(ccb->ccb_dmamap_xfer->dm_segs[i].ds_len);
  353                         sgb->addr =
  354                             htole32(ccb->ccb_dmamap_xfer->dm_segs[i].ds_addr);
  355                 }
  356         } else {
  357                 size = datasize;
  358                 nsegs = 0;
  359         }
  360 
  361         ccb->ccb_hdr.drive = drive;
  362         ccb->ccb_hdr.priority = 0;
  363         ccb->ccb_hdr.size = htole16((sizeof(struct cac_req) +
  364             sizeof(struct cac_sgb) * CAC_SG_SIZE) >> 2);
  365 
  366         ccb->ccb_req.next = 0;
  367         ccb->ccb_req.command = command;
  368         ccb->ccb_req.error = 0;
  369         ccb->ccb_req.blkno = htole32(blkno);
  370         ccb->ccb_req.bcount = htole16(howmany(size, DEV_BSIZE));
  371         ccb->ccb_req.sgcount = nsegs;
  372         ccb->ccb_req.reserved = 0;
  373 
  374         ccb->ccb_flags = flags;
  375         ccb->ccb_datasize = size;
  376         ccb->ccb_xs = xs;
  377 
  378         if (!xs || xs->flags & SCSI_POLL) {
  379 
  380                 /* Synchronous commands musn't wait. */
  381                 if ((*sc->sc_cl->cl_fifo_full)(sc)) {
  382                         cac_ccb_free(sc, ccb);
  383                         rv = -1;
  384                 } else {
  385                         ccb->ccb_flags |= CAC_CCB_ACTIVE;
  386                         (*sc->sc_cl->cl_submit)(sc, ccb);
  387                         rv = cac_ccb_poll(sc, ccb, 2000);
  388                 }
  389         } else
  390                 rv = cac_ccb_start(sc, ccb);
  391 
  392         return (rv);
  393 }
  394 
  395 /*
  396  * Wait for the specified CCB to complete.  Must be called at splbio.
  397  */
  398 int
  399 cac_ccb_poll(struct cac_softc *sc, struct cac_ccb *wantccb, int timo)
  400 {
  401         struct cac_ccb *ccb;
  402         int t = timo * 10;
  403 
  404         do {
  405                 for (; t--; DELAY(100))
  406                         if ((ccb = (*sc->sc_cl->cl_completed)(sc)) != NULL)
  407                                 break;
  408                 if (t < 0) {
  409                         printf("%s: timeout\n", sc->sc_dv.dv_xname);
  410                         return (EBUSY);
  411                 }
  412                 cac_ccb_done(sc, ccb);
  413         } while (ccb != wantccb);
  414 
  415         return (0);
  416 }
  417 
  418 /*
  419  * Enqueue the specified command (if any) and attempt to start all enqueued
  420  * commands.  Must be called at splbio.
  421  */
  422 int
  423 cac_ccb_start(struct cac_softc *sc, struct cac_ccb *ccb)
  424 {
  425         if (ccb != NULL)
  426                 SIMPLEQ_INSERT_TAIL(&sc->sc_ccb_queue, ccb, ccb_chain);
  427 
  428         while ((ccb = SIMPLEQ_FIRST(&sc->sc_ccb_queue)) != NULL &&
  429             !(*sc->sc_cl->cl_fifo_full)(sc)) {
  430                 SIMPLEQ_REMOVE_HEAD(&sc->sc_ccb_queue, ccb_chain);
  431                 ccb->ccb_flags |= CAC_CCB_ACTIVE;
  432                 (*sc->sc_cl->cl_submit)(sc, ccb);
  433         }
  434 
  435         return (0);
  436 }
  437 
  438 /*
  439  * Process a finished CCB.
  440  */
  441 void
  442 cac_ccb_done(struct cac_softc *sc, struct cac_ccb *ccb)
  443 {
  444         struct scsi_xfer *xs = ccb->ccb_xs;
  445         int error = 0;
  446 
  447         if ((ccb->ccb_flags & CAC_CCB_ACTIVE) == 0) {
  448                 printf("%s: CCB not active, xs=%p\n", sc->sc_dv.dv_xname, xs);
  449                 if (xs) {
  450                         xs->error = XS_DRIVER_STUFFUP;
  451                         scsi_done(xs);
  452                 }
  453                 return;
  454         }
  455 
  456         if ((ccb->ccb_flags & (CAC_CCB_DATA_IN | CAC_CCB_DATA_OUT)) != 0) {
  457                 bus_dmamap_sync(sc->sc_dmat, ccb->ccb_dmamap_xfer, 0,
  458                     ccb->ccb_dmamap_xfer->dm_mapsize,
  459                     ccb->ccb_flags & CAC_CCB_DATA_IN ?
  460                     BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);
  461                 bus_dmamap_unload(sc->sc_dmat, ccb->ccb_dmamap_xfer);
  462         }
  463 
  464         if ((ccb->ccb_req.error & CAC_RET_SOFT_ERROR) != 0)
  465                 printf("%s: soft error; corrected\n", sc->sc_dv.dv_xname);
  466         if ((ccb->ccb_req.error & CAC_RET_HARD_ERROR) != 0) {
  467                 error = 1;
  468                 printf("%s: hard error\n", sc->sc_dv.dv_xname);
  469         }
  470         if ((ccb->ccb_req.error & CAC_RET_CMD_REJECTED) != 0) {
  471                 error = 1;
  472                 printf("%s: invalid request\n", sc->sc_dv.dv_xname);
  473         }
  474 
  475         cac_ccb_free(sc, ccb);
  476         if (xs) {
  477                 if (error)
  478                         xs->error = XS_DRIVER_STUFFUP;
  479                 else
  480                         xs->resid = 0;
  481 
  482                 xs->flags |= ITSDONE;
  483                 scsi_done(xs);
  484         }
  485 }
  486 
  487 /*
  488  * Allocate a CCB.
  489  */
  490 struct cac_ccb *
  491 cac_ccb_alloc(struct cac_softc *sc, int nosleep)
  492 {
  493         struct cac_ccb *ccb;
  494 
  495         if ((ccb = SIMPLEQ_FIRST(&sc->sc_ccb_free)) != NULL)
  496                 SIMPLEQ_REMOVE_HEAD(&sc->sc_ccb_free, ccb_chain);
  497         else
  498                 ccb = NULL;
  499         return (ccb);
  500 }
  501 
  502 /*
  503  * Put a CCB onto the freelist.
  504  */
  505 void
  506 cac_ccb_free(struct cac_softc *sc, struct cac_ccb *ccb)
  507 {
  508 
  509         ccb->ccb_flags = 0;
  510         SIMPLEQ_INSERT_HEAD(&sc->sc_ccb_free, ccb, ccb_chain);
  511 }
  512 
  513 int
  514 cac_get_dinfo(sc, target)
  515         struct cac_softc *sc;
  516         int target;
  517 {
  518         if (sc->sc_dinfos[target].ncylinders)
  519                 return (0);
  520 
  521         if (cac_cmd(sc, CAC_CMD_GET_LOG_DRV_INFO, &sc->sc_dinfos[target],
  522             sizeof(*sc->sc_dinfos), target, 0, CAC_CCB_DATA_IN, NULL)) {
  523                 printf("%s: CMD_GET_LOG_DRV_INFO failed\n",
  524                     sc->sc_dv.dv_xname);
  525                 return (-1);
  526         }
  527 
  528         return (0);
  529 }
  530 
  531 void
  532 cacminphys(bp)
  533         struct buf *bp;
  534 {
  535         if (bp->b_bcount > CAC_MAX_XFER)
  536                 bp->b_bcount = CAC_MAX_XFER;
  537         minphys(bp);
  538 }
  539 
  540 void
  541 cac_copy_internal_data(xs, v, size)
  542         struct scsi_xfer *xs;
  543         void *v;
  544         size_t size;
  545 {
  546         size_t copy_cnt;
  547 
  548         if (!xs->datalen)
  549                 printf("uio move is not yet supported\n");
  550         else {
  551                 copy_cnt = MIN(size, xs->datalen);
  552                 bcopy(v, xs->data, copy_cnt);
  553         }
  554 }
  555 
  556 int
  557 cac_scsi_cmd(xs)
  558         struct scsi_xfer *xs;
  559 {
  560         struct scsi_link *link = xs->sc_link;
  561         struct cac_softc *sc = link->adapter_softc;
  562         struct cac_drive_info *dinfo;
  563         struct scsi_inquiry_data inq;
  564         struct scsi_sense_data sd;
  565         struct scsi_read_cap_data rcd;
  566         u_int8_t target = link->target;
  567         u_int32_t blockno, blockcnt, size;
  568         struct scsi_rw *rw;
  569         struct scsi_rw_big *rwb;
  570         int op, flags, s, error, poll;
  571         const char *p;
  572 
  573         if (target >= sc->sc_nunits || link->lun != 0) {
  574                 xs->error = XS_DRIVER_STUFFUP;
  575                 return (COMPLETE);
  576         }
  577 
  578         s = splbio();
  579         xs->error = XS_NOERROR;
  580         xs->free_list.le_next = NULL;
  581         dinfo = &sc->sc_dinfos[target];
  582 
  583         switch (xs->cmd->opcode) {
  584         case TEST_UNIT_READY:
  585         case START_STOP:
  586 #if 0
  587         case VERIFY:
  588 #endif
  589                 break;
  590 
  591         case REQUEST_SENSE:
  592                 bzero(&sd, sizeof sd);
  593                 sd.error_code = 0x70;
  594                 sd.segment = 0;
  595                 sd.flags = SKEY_NO_SENSE;
  596                 *(u_int32_t*)sd.info = htole32(0);
  597                 sd.extra_len = 0;
  598                 cac_copy_internal_data(xs, &sd, sizeof sd);
  599                 break;
  600 
  601         case INQUIRY:
  602                 if (cac_get_dinfo(sc, target)) {
  603                         xs->error = XS_DRIVER_STUFFUP;
  604                         break;
  605                 }
  606                 bzero(&inq, sizeof inq);
  607                 inq.device = T_DIRECT;
  608                 inq.dev_qual2 = 0;
  609                 inq.version = 2;
  610                 inq.response_format = 2;
  611                 inq.additional_length = 32;
  612                 strlcpy(inq.vendor, "Compaq  ", sizeof inq.vendor);
  613                 switch (CAC_GET1(dinfo->mirror)) {
  614                 case 0: p = "RAID0";    break;
  615                 case 1: p = "RAID4";    break;
  616                 case 2: p = "RAID1";    break;
  617                 case 3: p = "RAID5";    break;
  618                 default:p = "<UNK>";    break;
  619                 }
  620                 snprintf(inq.product, sizeof inq.product, "%s vol  #%02d",
  621                     p, target);
  622                 strlcpy(inq.revision, "   ", sizeof inq.revision);
  623                 cac_copy_internal_data(xs, &inq, sizeof inq);
  624                 break;
  625 
  626         case READ_CAPACITY:
  627                 if (cac_get_dinfo(sc, target)) {
  628                         xs->error = XS_DRIVER_STUFFUP;
  629                         break;
  630                 }
  631                 bzero(&rcd, sizeof rcd);
  632                 _lto4b( CAC_GET2(dinfo->ncylinders) * CAC_GET1(dinfo->nheads) *
  633                     CAC_GET1(dinfo->nsectors) - 1, rcd.addr);
  634                 _lto4b(CAC_SECTOR_SIZE, rcd.length);
  635                 cac_copy_internal_data(xs, &rcd, sizeof rcd);
  636                 break;
  637 
  638         case PREVENT_ALLOW:
  639                 break;
  640 
  641         case SYNCHRONIZE_CACHE:
  642                 if (cac_flush(sc))
  643                         xs->error = XS_DRIVER_STUFFUP;
  644                 break;
  645 
  646         case READ_COMMAND:
  647         case READ_BIG:
  648         case WRITE_COMMAND:
  649         case WRITE_BIG:
  650 
  651                 flags = 0;
  652                 /* A read or write operation. */
  653                 if (xs->cmdlen == 6) {
  654                         rw = (struct scsi_rw *)xs->cmd;
  655                         blockno = _3btol(rw->addr) &
  656                             (SRW_TOPADDR << 16 | 0xffff);
  657                         blockcnt = rw->length ? rw->length : 0x100;
  658                 } else {
  659                         rwb = (struct scsi_rw_big *)xs->cmd;
  660                         blockno = _4btol(rwb->addr);
  661                         blockcnt = _2btol(rwb->length);
  662                 }
  663                 size = CAC_GET2(dinfo->ncylinders) *
  664                     CAC_GET1(dinfo->nheads) * CAC_GET1(dinfo->nsectors);
  665                 if (blockno >= size || blockno + blockcnt > size) {
  666                         printf("%s: out of bounds %u-%u >= %u\n",
  667                             sc->sc_dv.dv_xname, blockno, blockcnt, size);
  668                         xs->error = XS_DRIVER_STUFFUP;
  669                         scsi_done(xs);
  670                         break;
  671                 }
  672 
  673                 switch (xs->cmd->opcode) {
  674                 case READ_COMMAND:
  675                 case READ_BIG:
  676                         op = CAC_CMD_READ;
  677                         flags = CAC_CCB_DATA_IN;
  678                         break;
  679                 case WRITE_COMMAND:
  680                 case WRITE_BIG:
  681                         op = CAC_CMD_WRITE;
  682                         flags = CAC_CCB_DATA_OUT;
  683                         break;
  684                 }
  685 
  686                 poll = xs->flags & SCSI_POLL;
  687                 if ((error = cac_cmd(sc, op, xs->data, blockcnt * DEV_BSIZE,
  688                     target, blockno, flags, xs))) {
  689 
  690                         if (error == ENOMEM) {
  691                                 splx(s);
  692                                 return (TRY_AGAIN_LATER);
  693                         } else if (poll) {
  694                                 splx(s);
  695                                 return (TRY_AGAIN_LATER);
  696                         } else {
  697                                 xs->error = XS_DRIVER_STUFFUP;
  698                                 scsi_done(xs);
  699                                 break;
  700                         }
  701                 }
  702 
  703                 splx(s);
  704 
  705                 if (poll)
  706                         return (COMPLETE);
  707                 else
  708                         return (SUCCESSFULLY_QUEUED);
  709 
  710         default:
  711                 SC_DEBUG(link, SDEV_DB1, ("unsupported scsi command %#x "
  712                     "tgt %d ", xs->cmd->opcode, target));
  713                 xs->error = XS_DRIVER_STUFFUP;
  714         }
  715         splx(s);
  716 
  717         return (COMPLETE);
  718 }
  719 
  720 /*
  721  * Board specific linkage shared between multiple bus types.
  722  */
  723 
  724 int
  725 cac_l0_fifo_full(struct cac_softc *sc)
  726 {
  727 
  728         return (cac_inl(sc, CAC_REG_CMD_FIFO) == 0);
  729 }
  730 
  731 void
  732 cac_l0_submit(struct cac_softc *sc, struct cac_ccb *ccb)
  733 {
  734 #ifdef CAC_DEBUG
  735         printf("submit-%x ", ccb->ccb_paddr);
  736 #endif
  737         bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap, 0,
  738             sc->sc_dmamap->dm_mapsize,
  739             BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
  740         cac_outl(sc, CAC_REG_CMD_FIFO, ccb->ccb_paddr);
  741 }
  742 
  743 struct cac_ccb *
  744 cac_l0_completed(sc)
  745         struct cac_softc *sc;
  746 {
  747         struct cac_ccb *ccb;
  748         paddr_t off;
  749 
  750         if (!(off = cac_inl(sc, CAC_REG_DONE_FIFO)))
  751                 return NULL;
  752 #ifdef CAC_DEBUG
  753         printf("compl-%x ", off);
  754 #endif
  755         if (off & 3 && ccb->ccb_req.error == 0)
  756                 ccb->ccb_req.error = CAC_RET_CMD_INVALID;
  757 
  758         off = (off & ~3) - sc->sc_ccbs_paddr;
  759         ccb = (struct cac_ccb *)(sc->sc_ccbs + off);
  760 
  761         bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap, 0,
  762             sc->sc_dmamap->dm_mapsize,
  763             BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD);
  764 
  765         return (ccb);
  766 }
  767 
  768 int
  769 cac_l0_intr_pending(struct cac_softc *sc)
  770 {
  771 
  772         return (cac_inl(sc, CAC_REG_INTR_PENDING));
  773 }
  774 
  775 void
  776 cac_l0_intr_enable(struct cac_softc *sc, int state)
  777 {
  778 
  779         cac_outl(sc, CAC_REG_INTR_MASK,
  780             state ? CAC_INTR_ENABLE : CAC_INTR_DISABLE);
  781 }

/* [<][>][^][v][top][bottom][index][help] */