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/uha.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: uha.c,v 1.42 2022/04/16 19:19:59 naddy Exp $  */
    2 /*      $NetBSD: uha.c,v 1.3 1996/10/13 01:37:29 christos Exp $ */
    3 /*
    4  * Copyright (c) 1994, 1996 Charles M. Hannum.  All rights reserved.
    5  *
    6  * Redistribution and use in source and binary forms, with or without
    7  * modification, are permitted provided that the following conditions
    8  * are met:
    9  * 1. Redistributions of source code must retain the above copyright
   10  *    notice, this list of conditions and the following disclaimer.
   11  * 2. Redistributions in binary form must reproduce the above copyright
   12  *    notice, this list of conditions and the following disclaimer in the
   13  *    documentation and/or other materials provided with the distribution.
   14  * 3. All advertising materials mentioning features or use of this software
   15  *    must display the following acknowledgement:
   16  *      This product includes software developed by Charles M. Hannum.
   17  * 4. The name of the author may not be used to endorse or promote products
   18  *    derived from this software without specific prior written permission.
   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 BE LIABLE FOR ANY DIRECT, INDIRECT,
   24  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   25  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   26  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   27  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   28  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   29  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   30  */
   31 
   32 /*
   33  * Ported for use with the UltraStor 14f by Gary Close (gclose@wvnvms.wvnet.edu)
   34  * Slight fixes to timeouts to run with the 34F
   35  * Thanks to Julian Elischer for advice and help with this port.
   36  *
   37  * Originally written by Julian Elischer (julian@tfs.com)
   38  * for TRW Financial Systems for use under the MACH(2.5) operating system.
   39  *
   40  * TRW Financial Systems, in accordance with their agreement with Carnegie
   41  * Mellon University, makes this software available to CMU to distribute
   42  * or use in any manner that they see fit as long as this message is kept with
   43  * the software. For this reason TFS also grants any other persons or
   44  * organisations permission to use or modify this software.
   45  *
   46  * TFS supplies this software to be publicly redistributed
   47  * on the understanding that TFS is not responsible for the correct
   48  * functioning of this software in any circumstances.
   49  *
   50  * commenced: Sun Sep 27 18:14:01 PDT 1992
   51  * slight mod to make work with 34F as well: Wed Jun  2 18:05:48 WST 1993
   52  */
   53 
   54 #include <sys/param.h>
   55 #include <sys/systm.h>
   56 #include <sys/kernel.h>
   57 #include <sys/errno.h>
   58 #include <sys/ioctl.h>
   59 #include <sys/device.h>
   60 #include <sys/malloc.h>
   61 #include <sys/buf.h>
   62 #include <uvm/uvm_extern.h>
   63 
   64 #include <machine/bus.h>
   65 #include <machine/intr.h>
   66 
   67 #include <scsi/scsi_all.h>
   68 #include <scsi/scsiconf.h>
   69 
   70 #include <dev/ic/uhareg.h>
   71 #include <dev/ic/uhavar.h>
   72 
   73 #define KVTOPHYS(x)     vtophys((vaddr_t)x)
   74 
   75 void uha_reset_mscp(struct uha_softc *, struct uha_mscp *);
   76 void uha_mscp_free(void *, void *);
   77 void *uha_mscp_alloc(void *);
   78 void uha_scsi_cmd(struct scsi_xfer *);
   79 int uhaprint(void *, const char *);
   80 
   81 const struct scsi_adapter uha_switch = {
   82         uha_scsi_cmd, NULL, NULL, NULL, NULL
   83 };
   84 
   85 struct cfdriver uha_cd = {
   86         NULL, "uha", DV_DULL
   87 };
   88 
   89 #define UHA_ABORT_TIMEOUT       2000    /* time to wait for abort (mSec) */
   90 
   91 int
   92 uhaprint(void *aux, const char *name)
   93 {
   94         if (name != NULL)
   95                 printf("%s: scsibus ", name);
   96         return UNCONF;
   97 }
   98 
   99 /*
  100  * Attach all the sub-devices we can find
  101  */
  102 void
  103 uha_attach(struct uha_softc *sc)
  104 {
  105         struct scsibus_attach_args saa;
  106 
  107         (sc->init)(sc);
  108         SLIST_INIT(&sc->sc_free_mscp);
  109 
  110         mtx_init(&sc->sc_mscp_mtx, IPL_BIO);
  111         scsi_iopool_init(&sc->sc_iopool, sc, uha_mscp_alloc, uha_mscp_free);
  112 
  113         saa.saa_adapter_softc = sc;
  114         saa.saa_adapter_target = sc->sc_scsi_dev;
  115         saa.saa_adapter = &uha_switch;
  116         saa.saa_luns = saa.saa_adapter_buswidth = 8;
  117         saa.saa_openings = 2;
  118         saa.saa_pool = &sc->sc_iopool;
  119         saa.saa_quirks = saa.saa_flags = 0;
  120         saa.saa_wwpn = saa.saa_wwnn = 0;
  121 
  122         config_found(&sc->sc_dev, &saa, uhaprint);
  123 }
  124 
  125 void
  126 uha_reset_mscp(struct uha_softc *sc, struct uha_mscp *mscp)
  127 {
  128 
  129         mscp->flags = 0;
  130 }
  131 
  132 /*
  133  * A mscp (and hence a mbx-out) is put onto the free list.
  134  */
  135 void
  136 uha_mscp_free(void *xsc, void *xmscp)
  137 {
  138         struct uha_softc *sc = xsc;
  139         struct uha_mscp *mscp = xmscp;
  140 
  141         uha_reset_mscp(sc, mscp);
  142 
  143         mtx_enter(&sc->sc_mscp_mtx);
  144         SLIST_INSERT_HEAD(&sc->sc_free_mscp, mscp, chain);
  145         mtx_leave(&sc->sc_mscp_mtx);
  146 }
  147 
  148 /*
  149  * Get a free mscp
  150  */
  151 void *
  152 uha_mscp_alloc(void *xsc)
  153 {
  154         struct uha_softc *sc = xsc;
  155         struct uha_mscp *mscp;
  156 
  157         mtx_enter(&sc->sc_mscp_mtx);
  158         mscp = SLIST_FIRST(&sc->sc_free_mscp);
  159         if (mscp) {
  160                 SLIST_REMOVE_HEAD(&sc->sc_free_mscp, chain);
  161                 mscp->flags |= MSCP_ALLOC;
  162         }
  163         mtx_leave(&sc->sc_mscp_mtx);
  164 
  165         return (mscp);
  166 }
  167 
  168 /*
  169  * given a physical address, find the mscp that it corresponds to.
  170  */
  171 struct uha_mscp *
  172 uha_mscp_phys_kv(struct uha_softc *sc, u_long mscp_phys)
  173 {
  174         int hashnum = MSCP_HASH(mscp_phys);
  175         struct uha_mscp *mscp = sc->sc_mscphash[hashnum];
  176 
  177         while (mscp) {
  178                 if (mscp->hashkey == mscp_phys)
  179                         break;
  180                 mscp = mscp->nexthash;
  181         }
  182         return (mscp);
  183 }
  184 
  185 /*
  186  * We have a mscp which has been processed by the adaptor, now we look to see
  187  * how the operation went.
  188  */
  189 void
  190 uha_done(struct uha_softc *sc, struct uha_mscp *mscp)
  191 {
  192         struct scsi_sense_data *s1, *s2;
  193         struct scsi_xfer *xs = mscp->xs;
  194 
  195 #ifdef UHADEBUG
  196         printf("%s: uha_done\n", sc->sc_dev.dv_xname);
  197 #endif
  198 
  199         /*
  200          * Otherwise, put the results of the operation
  201          * into the xfer and call whoever started it
  202          */
  203         if ((mscp->flags & MSCP_ALLOC) == 0) {
  204                 panic("%s: exiting ccb not allocated!", sc->sc_dev.dv_xname);
  205                 return;
  206         }
  207         if (xs->error == XS_NOERROR) {
  208                 if (mscp->host_stat != UHA_NO_ERR) {
  209                         switch (mscp->host_stat) {
  210                         case UHA_SBUS_TIMEOUT:          /* No response */
  211                                 xs->error = XS_SELTIMEOUT;
  212                                 break;
  213                         default:        /* Other scsi protocol messes */
  214                                 printf("%s: host_stat %x\n",
  215                                     sc->sc_dev.dv_xname, mscp->host_stat);
  216                                 xs->error = XS_DRIVER_STUFFUP;
  217                         }
  218                 } else if (mscp->target_stat != SCSI_OK) {
  219                         switch (mscp->target_stat) {
  220                         case SCSI_CHECK:
  221                                 s1 = &mscp->mscp_sense;
  222                                 s2 = &xs->sense;
  223                                 *s2 = *s1;
  224                                 xs->error = XS_SENSE;
  225                                 break;
  226                         case SCSI_BUSY:
  227                                 xs->error = XS_BUSY;
  228                                 break;
  229                         default:
  230                                 printf("%s: target_stat %x\n",
  231                                     sc->sc_dev.dv_xname, mscp->target_stat);
  232                                 xs->error = XS_DRIVER_STUFFUP;
  233                         }
  234                 } else
  235                         xs->resid = 0;
  236         }
  237 
  238         scsi_done(xs);
  239 }
  240 
  241 /*
  242  * start a scsi operation given the command and the data address.  Also
  243  * needs the unit, target and lu.
  244  */
  245 void
  246 uha_scsi_cmd(struct scsi_xfer *xs)
  247 {
  248         struct scsi_link *sc_link = xs->sc_link;
  249         struct uha_softc *sc = sc_link->bus->sb_adapter_softc;
  250         struct uha_mscp *mscp;
  251         struct uha_dma_seg *sg;
  252         int seg;                /* scatter gather seg being worked on */
  253         u_long thiskv, thisphys, nextphys;
  254         int bytes_this_seg, bytes_this_page, datalen, flags;
  255         int s;
  256 
  257 #ifdef UHADEBUG
  258         printf("%s: uha_scsi_cmd\n", sc->sc_dev.dv_xname);
  259 #endif
  260         /*
  261          * get a mscp (mbox-out) to use. If the transfer
  262          * is from a buf (possibly from interrupt time)
  263          * then we can't allow it to sleep
  264          */
  265         flags = xs->flags;
  266         mscp = xs->io;
  267 
  268         mscp->xs = xs;
  269         mscp->timeout = xs->timeout;
  270         timeout_set(&xs->stimeout, uha_timeout, xs);
  271 
  272         /*
  273          * Put all the arguments for the xfer in the mscp
  274          */
  275         if (flags & SCSI_RESET) {
  276                 mscp->opcode = UHA_SDR;
  277                 mscp->ca = 0x01;
  278         } else {
  279                 mscp->opcode = UHA_TSP;
  280                 /* XXX Not for tapes. */
  281                 mscp->ca = 0x01;
  282                 bcopy(&xs->cmd, &mscp->scsi_cmd, mscp->scsi_cmd_length);
  283         }
  284         mscp->xdir = UHA_SDET;
  285         mscp->dcn = 0x00;
  286         mscp->chan = 0x00;
  287         mscp->target = sc_link->target;
  288         mscp->lun = sc_link->lun;
  289         mscp->scsi_cmd_length = xs->cmdlen;
  290         mscp->sense_ptr = KVTOPHYS(&mscp->mscp_sense);
  291         mscp->req_sense_length = sizeof(mscp->mscp_sense);
  292         mscp->host_stat = 0x00;
  293         mscp->target_stat = 0x00;
  294 
  295         if (xs->datalen) {
  296                 sg = mscp->uha_dma;
  297                 seg = 0;
  298 
  299                 /*
  300                  * Set up the scatter gather block
  301                  */
  302 #ifdef UHADEBUG
  303                 printf("%s: %d @%p- ", sc->sc_dev.dv_xname, xs->datalen, xs->data);
  304 #endif
  305                 datalen = xs->datalen;
  306                 thiskv = (int) xs->data;
  307                 thisphys = KVTOPHYS(thiskv);
  308 
  309                 while (datalen && seg < UHA_NSEG) {
  310                         bytes_this_seg = 0;
  311 
  312                         /* put in the base address */
  313                         sg->seg_addr = thisphys;
  314 
  315 #ifdef UHADEBUG
  316                         printf("0x%lx", thisphys);
  317 #endif
  318 
  319                         /* do it at least once */
  320                         nextphys = thisphys;
  321                         while (datalen && thisphys == nextphys) {
  322                                 /*
  323                                  * This page is contiguous (physically)
  324                                  * with the last, just extend the
  325                                  * length
  326                                  */
  327                                 /* how far to the end of the page */
  328                                 nextphys = (thisphys & ~PGOFSET) + NBPG;
  329                                 bytes_this_page = nextphys - thisphys;
  330                                 /**** or the data ****/
  331                                 bytes_this_page = min(bytes_this_page,
  332                                                       datalen);
  333                                 bytes_this_seg += bytes_this_page;
  334                                 datalen -= bytes_this_page;
  335 
  336                                 /* get more ready for the next page */
  337                                 thiskv = (thiskv & ~PGOFSET) + NBPG;
  338                                 if (datalen)
  339                                         thisphys = KVTOPHYS(thiskv);
  340                         }
  341                         /*
  342                          * next page isn't contiguous, finish the seg
  343                          */
  344 #ifdef UHADEBUG
  345                         printf("(0x%x)", bytes_this_seg);
  346 #endif
  347                         sg->seg_len = bytes_this_seg;
  348                         sg++;
  349                         seg++;
  350                 }
  351 
  352 #ifdef UHADEBUG
  353                 printf("\n");
  354 #endif
  355                 if (datalen) {
  356                         /*
  357                          * there's still data, must have run out of segs!
  358                          */
  359                         printf("%s: uha_scsi_cmd, more than %d dma segs\n",
  360                             sc->sc_dev.dv_xname, UHA_NSEG);
  361                         goto bad;
  362                 }
  363                 mscp->data_addr = KVTOPHYS(mscp->uha_dma);
  364                 mscp->data_length = xs->datalen;
  365                 mscp->sgth = 0x01;
  366                 mscp->sg_num = seg;
  367         } else {                /* No data xfer, use non S/G values */
  368                 mscp->data_addr = (physaddr)0;
  369                 mscp->data_length = 0;
  370                 mscp->sgth = 0x00;
  371                 mscp->sg_num = 0;
  372         }
  373         mscp->link_id = 0;
  374         mscp->link_addr = (physaddr)0;
  375 
  376         s = splbio();
  377         (sc->start_mbox)(sc, mscp);
  378         splx(s);
  379 
  380         /*
  381          * Usually return SUCCESSFULLY QUEUED
  382          */
  383         if ((flags & SCSI_POLL) == 0)
  384                 return;
  385 
  386         /*
  387          * If we can't use interrupts, poll on completion
  388          */
  389         if ((sc->poll)(sc, xs, mscp->timeout)) {
  390                 uha_timeout(mscp);
  391                 if ((sc->poll)(sc, xs, mscp->timeout))
  392                         uha_timeout(mscp);
  393         }
  394         return;
  395 
  396 bad:
  397         xs->error = XS_DRIVER_STUFFUP;
  398         scsi_done(xs);
  399         return;
  400 }
  401 
  402 void
  403 uha_timeout(void *arg)
  404 {
  405         struct uha_mscp *mscp = arg;
  406         struct scsi_xfer *xs = mscp->xs;
  407         struct scsi_link *sc_link = xs->sc_link;
  408         struct uha_softc *sc = sc_link->bus->sb_adapter_softc;
  409         int s;
  410 
  411         sc_print_addr(sc_link);
  412         printf("timed out");
  413 
  414         s = splbio();
  415 
  416         if (mscp->flags & MSCP_ABORT) {
  417                 /* abort timed out */
  418                 printf(" AGAIN\n");
  419                 /* XXX Must reset! */
  420         } else {
  421                 /* abort the operation that has timed out */
  422                 printf("\n");
  423                 mscp->xs->error = XS_TIMEOUT;
  424                 mscp->timeout = UHA_ABORT_TIMEOUT;
  425                 mscp->flags |= MSCP_ABORT;
  426                 (sc->start_mbox)(sc, mscp);
  427         }
  428 
  429         splx(s);
  430 }

Cache object: 53224db297eb4078cc08743f8c550cf5


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