root/dev/ic/uha.c

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

DEFINITIONS

This source file includes following definitions.
  1. uhaprint
  2. uha_attach
  3. uha_reset_mscp
  4. uha_free_mscp
  5. uha_init_mscp
  6. uha_get_mscp
  7. uha_mscp_phys_kv
  8. uha_done
  9. uhaminphys
  10. uha_scsi_cmd
  11. uha_timeout

    1 /*      $OpenBSD: uha.c,v 1.9 2006/11/28 23:59:45 dlg Exp $     */
    2 /*      $NetBSD: uha.c,v 1.3 1996/10/13 01:37:29 christos Exp $ */
    3 
    4 #undef UHADEBUG
    5 #ifdef DDB
    6 #define integrate
    7 #else
    8 #define integrate       static inline
    9 #endif
   10 
   11 /*
   12  * Copyright (c) 1994, 1996 Charles M. Hannum.  All rights reserved.
   13  *
   14  * Redistribution and use in source and binary forms, with or without
   15  * modification, are permitted provided that the following conditions
   16  * are met:
   17  * 1. Redistributions of source code must retain the above copyright
   18  *    notice, this list of conditions and the following disclaimer.
   19  * 2. Redistributions in binary form must reproduce the above copyright
   20  *    notice, this list of conditions and the following disclaimer in the
   21  *    documentation and/or other materials provided with the distribution.
   22  * 3. All advertising materials mentioning features or use of this software
   23  *    must display the following acknowledgement:
   24  *      This product includes software developed by Charles M. Hannum.
   25  * 4. The name of the author may not be used to endorse or promote products
   26  *    derived from this software without specific prior written permission.
   27  *
   28  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   29  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   30  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   31  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   32  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   33  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   34  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   35  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   36  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   37  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   38  */
   39 
   40 /*
   41  * Ported for use with the UltraStor 14f by Gary Close (gclose@wvnvms.wvnet.edu)
   42  * Slight fixes to timeouts to run with the 34F
   43  * Thanks to Julian Elischer for advice and help with this port.
   44  *
   45  * Originally written by Julian Elischer (julian@tfs.com)
   46  * for TRW Financial Systems for use under the MACH(2.5) operating system.
   47  *
   48  * TRW Financial Systems, in accordance with their agreement with Carnegie
   49  * Mellon University, makes this software available to CMU to distribute
   50  * or use in any manner that they see fit as long as this message is kept with
   51  * the software. For this reason TFS also grants any other persons or
   52  * organisations permission to use or modify this software.
   53  *
   54  * TFS supplies this software to be publicly redistributed
   55  * on the understanding that TFS is not responsible for the correct
   56  * functioning of this software in any circumstances.
   57  *
   58  * commenced: Sun Sep 27 18:14:01 PDT 1992
   59  * slight mod to make work with 34F as well: Wed Jun  2 18:05:48 WST 1993
   60  */
   61 
   62 #include <sys/types.h>
   63 #include <sys/param.h>
   64 #include <sys/systm.h>
   65 #include <sys/kernel.h>
   66 #include <sys/errno.h>
   67 #include <sys/ioctl.h>
   68 #include <sys/device.h>
   69 #include <sys/malloc.h>
   70 #include <sys/buf.h>
   71 #include <sys/proc.h>
   72 #include <sys/user.h>
   73 
   74 #include <machine/bus.h>
   75 #include <machine/intr.h>
   76 
   77 #include <scsi/scsi_all.h>
   78 #include <scsi/scsiconf.h>
   79 
   80 #include <dev/ic/uhareg.h>
   81 #include <dev/ic/uhavar.h>
   82 
   83 #ifndef DDB
   84 #define Debugger() panic("should call debugger here (ultra14f.c)")
   85 #endif /* ! DDB */
   86 
   87 #define KVTOPHYS(x)     vtophys((vaddr_t)x)
   88 
   89 integrate void uha_reset_mscp(struct uha_softc *, struct uha_mscp *);
   90 void uha_free_mscp(struct uha_softc *, struct uha_mscp *);
   91 integrate void uha_init_mscp(struct uha_softc *, struct uha_mscp *);
   92 struct uha_mscp *uha_get_mscp(struct uha_softc *, int);
   93 void uhaminphys(struct buf *);
   94 int uha_scsi_cmd(struct scsi_xfer *);
   95 
   96 struct scsi_adapter uha_switch = {
   97         uha_scsi_cmd,
   98         uhaminphys,
   99         0,
  100         0,
  101 };
  102 
  103 /* the below structure is so we have a default dev struct for out link struct */
  104 struct scsi_device uha_dev = {
  105         NULL,                   /* Use default error handler */
  106         NULL,                   /* have a queue, served by this */
  107         NULL,                   /* have no async handler */
  108         NULL,                   /* Use default 'done' routine */
  109 };
  110 
  111 struct cfdriver uha_cd = {
  112         NULL, "uha", DV_DULL
  113 };
  114 
  115 #define UHA_ABORT_TIMEOUT       2000    /* time to wait for abort (mSec) */
  116 
  117 #ifdef __OpenBSD__
  118 int     uhaprint(void *, const char *);
  119 
  120 int
  121 uhaprint(aux, name)
  122         void *aux;
  123         const char *name;
  124 {
  125 
  126         if (name != NULL)
  127                 printf("%s: scsibus ", name);
  128         return UNCONF;
  129 }
  130 #endif
  131 
  132 /*
  133  * Attach all the sub-devices we can find
  134  */
  135 void
  136 uha_attach(sc)
  137         struct uha_softc *sc;
  138 {
  139         struct scsibus_attach_args saa;
  140 
  141         (sc->init)(sc);
  142         TAILQ_INIT(&sc->sc_free_mscp);
  143 
  144         /*
  145          * fill in the prototype scsi_link.
  146          */
  147         sc->sc_link.adapter_softc = sc;
  148         sc->sc_link.adapter_target = sc->sc_scsi_dev;
  149         sc->sc_link.adapter = &uha_switch;
  150         sc->sc_link.device = &uha_dev;
  151         sc->sc_link.openings = 2;
  152 
  153         bzero(&saa, sizeof(saa));
  154         saa.saa_sc_link = &sc->sc_link;
  155 
  156         /*
  157          * ask the adapter what subunits are present
  158          */
  159         config_found(&sc->sc_dev, &saa, uhaprint);
  160 }
  161 
  162 integrate void
  163 uha_reset_mscp(sc, mscp)
  164         struct uha_softc *sc;
  165         struct uha_mscp *mscp;
  166 {
  167 
  168         mscp->flags = 0;
  169 }
  170 
  171 /*
  172  * A mscp (and hence a mbx-out) is put onto the free list.
  173  */
  174 void
  175 uha_free_mscp(sc, mscp)
  176         struct uha_softc *sc;
  177         struct uha_mscp *mscp;
  178 {
  179         int s;
  180 
  181         s = splbio();
  182 
  183         uha_reset_mscp(sc, mscp);
  184         TAILQ_INSERT_HEAD(&sc->sc_free_mscp, mscp, chain);
  185 
  186         /*
  187          * If there were none, wake anybody waiting for one to come free,
  188          * starting with queued entries.
  189          */
  190         if (TAILQ_NEXT(mscp, chain) == NULL)
  191                 wakeup(&sc->sc_free_mscp);
  192 
  193         splx(s);
  194 }
  195 
  196 integrate void
  197 uha_init_mscp(sc, mscp)
  198         struct uha_softc *sc;
  199         struct uha_mscp *mscp;
  200 {
  201         int hashnum;
  202 
  203         bzero(mscp, sizeof(struct uha_mscp));
  204         /*
  205          * put in the phystokv hash table
  206          * Never gets taken out.
  207          */
  208         mscp->hashkey = KVTOPHYS(mscp);
  209         hashnum = MSCP_HASH(mscp->hashkey);
  210         mscp->nexthash = sc->sc_mscphash[hashnum];
  211         sc->sc_mscphash[hashnum] = mscp;
  212         uha_reset_mscp(sc, mscp);
  213 }
  214 
  215 /*
  216  * Get a free mscp
  217  *
  218  * If there are none, see if we can allocate a new one.  If so, put it in the
  219  * hash table too otherwise either return an error or sleep.
  220  */
  221 struct uha_mscp *
  222 uha_get_mscp(sc, flags)
  223         struct uha_softc *sc;
  224         int flags;
  225 {
  226         struct uha_mscp *mscp;
  227         int s;
  228 
  229         s = splbio();
  230 
  231         /*
  232          * If we can and have to, sleep waiting for one to come free
  233          * but only if we can't allocate a new one
  234          */
  235         for (;;) {
  236                 mscp = TAILQ_FIRST(&sc->sc_free_mscp);
  237                 if (mscp) {
  238                         TAILQ_REMOVE(&sc->sc_free_mscp, mscp, chain);
  239                         break;
  240                 }
  241                 if (sc->sc_nummscps < UHA_MSCP_MAX) {
  242                         mscp = (struct uha_mscp *) malloc(sizeof(struct uha_mscp),
  243                             M_TEMP, M_NOWAIT);
  244                         if (!mscp) {
  245                                 printf("%s: can't malloc mscp\n",
  246                                     sc->sc_dev.dv_xname);
  247                                 goto out;
  248                         }
  249                         uha_init_mscp(sc, mscp);
  250                         sc->sc_nummscps++;
  251                         break;
  252                 }
  253                 if ((flags & SCSI_NOSLEEP) != 0)
  254                         goto out;
  255                 tsleep(&sc->sc_free_mscp, PRIBIO, "uhamsc", 0);
  256         }
  257 
  258         mscp->flags |= MSCP_ALLOC;
  259 
  260 out:
  261         splx(s);
  262         return (mscp);
  263 }
  264 
  265 /*
  266  * given a physical address, find the mscp that it corresponds to.
  267  */
  268 struct uha_mscp *
  269 uha_mscp_phys_kv(sc, mscp_phys)
  270         struct uha_softc *sc;
  271         u_long mscp_phys;
  272 {
  273         int hashnum = MSCP_HASH(mscp_phys);
  274         struct uha_mscp *mscp = sc->sc_mscphash[hashnum];
  275 
  276         while (mscp) {
  277                 if (mscp->hashkey == mscp_phys)
  278                         break;
  279                 mscp = mscp->nexthash;
  280         }
  281         return (mscp);
  282 }
  283 
  284 /*
  285  * We have a mscp which has been processed by the adaptor, now we look to see
  286  * how the operation went.
  287  */
  288 void
  289 uha_done(sc, mscp)
  290         struct uha_softc *sc;
  291         struct uha_mscp *mscp;
  292 {
  293         struct scsi_sense_data *s1, *s2;
  294         struct scsi_xfer *xs = mscp->xs;
  295 
  296         SC_DEBUG(xs->sc_link, SDEV_DB2, ("uha_done\n"));
  297         /*
  298          * Otherwise, put the results of the operation
  299          * into the xfer and call whoever started it
  300          */
  301         if ((mscp->flags & MSCP_ALLOC) == 0) {
  302                 printf("%s: exiting ccb not allocated!\n", sc->sc_dev.dv_xname);
  303                 Debugger();
  304                 return;
  305         }
  306         if (xs->error == XS_NOERROR) {
  307                 if (mscp->host_stat != UHA_NO_ERR) {
  308                         switch (mscp->host_stat) {
  309                         case UHA_SBUS_TIMEOUT:          /* No response */
  310                                 xs->error = XS_SELTIMEOUT;
  311                                 break;
  312                         default:        /* Other scsi protocol messes */
  313                                 printf("%s: host_stat %x\n",
  314                                     sc->sc_dev.dv_xname, mscp->host_stat);
  315                                 xs->error = XS_DRIVER_STUFFUP;
  316                         }
  317                 } else if (mscp->target_stat != SCSI_OK) {
  318                         switch (mscp->target_stat) {
  319                         case SCSI_CHECK:
  320                                 s1 = &mscp->mscp_sense;
  321                                 s2 = &xs->sense;
  322                                 *s2 = *s1;
  323                                 xs->error = XS_SENSE;
  324                                 break;
  325                         case SCSI_BUSY:
  326                                 xs->error = XS_BUSY;
  327                                 break;
  328                         default:
  329                                 printf("%s: target_stat %x\n",
  330                                     sc->sc_dev.dv_xname, mscp->target_stat);
  331                                 xs->error = XS_DRIVER_STUFFUP;
  332                         }
  333                 } else
  334                         xs->resid = 0;
  335         }
  336         uha_free_mscp(sc, mscp);
  337         xs->flags |= ITSDONE;
  338         scsi_done(xs);
  339 }
  340 
  341 void
  342 uhaminphys(bp)
  343         struct buf *bp;
  344 {
  345 
  346         if (bp->b_bcount > ((UHA_NSEG - 1) << PGSHIFT))
  347                 bp->b_bcount = ((UHA_NSEG - 1) << PGSHIFT);
  348         minphys(bp);
  349 }
  350 
  351 /*
  352  * start a scsi operation given the command and the data address.  Also
  353  * needs the unit, target and lu.
  354  */
  355 int
  356 uha_scsi_cmd(xs)
  357         struct scsi_xfer *xs;
  358 {
  359         struct scsi_link *sc_link = xs->sc_link;
  360         struct uha_softc *sc = sc_link->adapter_softc;
  361         struct uha_mscp *mscp;
  362         struct uha_dma_seg *sg;
  363         int seg;                /* scatter gather seg being worked on */
  364         u_long thiskv, thisphys, nextphys;
  365         int bytes_this_seg, bytes_this_page, datalen, flags;
  366         int s;
  367 
  368         SC_DEBUG(sc_link, SDEV_DB2, ("uha_scsi_cmd\n"));
  369         /*
  370          * get a mscp (mbox-out) to use. If the transfer
  371          * is from a buf (possibly from interrupt time)
  372          * then we can't allow it to sleep
  373          */
  374         flags = xs->flags;
  375         if ((mscp = uha_get_mscp(sc, flags)) == NULL) {
  376                 return (TRY_AGAIN_LATER);
  377         }
  378         mscp->xs = xs;
  379         mscp->timeout = xs->timeout;
  380         timeout_set(&xs->stimeout, uha_timeout, xs);
  381 
  382         /*
  383          * Put all the arguments for the xfer in the mscp
  384          */
  385         if (flags & SCSI_RESET) {
  386                 mscp->opcode = UHA_SDR;
  387                 mscp->ca = 0x01;
  388         } else {
  389                 mscp->opcode = UHA_TSP;
  390                 /* XXX Not for tapes. */
  391                 mscp->ca = 0x01;
  392                 bcopy(xs->cmd, &mscp->scsi_cmd, mscp->scsi_cmd_length);
  393         }
  394         mscp->xdir = UHA_SDET;
  395         mscp->dcn = 0x00;
  396         mscp->chan = 0x00;
  397         mscp->target = sc_link->target;
  398         mscp->lun = sc_link->lun;
  399         mscp->scsi_cmd_length = xs->cmdlen;
  400         mscp->sense_ptr = KVTOPHYS(&mscp->mscp_sense);
  401         mscp->req_sense_length = sizeof(mscp->mscp_sense);
  402         mscp->host_stat = 0x00;
  403         mscp->target_stat = 0x00;
  404 
  405         if (xs->datalen) {
  406                 sg = mscp->uha_dma;
  407                 seg = 0;
  408 #ifdef  TFS
  409                 if (flags & SCSI_DATA_UIO) {
  410                         struct iovec *iovp;
  411                         iovp = ((struct uio *) xs->data)->uio_iov;
  412                         datalen = ((struct uio *) xs->data)->uio_iovcnt;
  413                         xs->datalen = 0;
  414                         while (datalen && seg < UHA_NSEG) {
  415                                 sg->seg_addr = (physaddr)iovp->iov_base;
  416                                 sg->seg_len = iovp->iov_len;
  417                                 xs->datalen += iovp->iov_len;
  418                                 SC_DEBUGN(sc_link, SDEV_DB4, ("(0x%x@0x%x)",
  419                                     iovp->iov_len, iovp->iov_base));
  420                                 sg++;
  421                                 iovp++;
  422                                 seg++;
  423                                 datalen--;
  424                         }
  425                 } else
  426 #endif /*TFS */
  427                 {
  428                         /*
  429                          * Set up the scatter gather block
  430                          */
  431                         SC_DEBUG(sc_link, SDEV_DB4,
  432                             ("%d @0x%x:- ", xs->datalen, xs->data));
  433                         datalen = xs->datalen;
  434                         thiskv = (int) xs->data;
  435                         thisphys = KVTOPHYS(thiskv);
  436 
  437                         while (datalen && seg < UHA_NSEG) {
  438                                 bytes_this_seg = 0;
  439 
  440                                 /* put in the base address */
  441                                 sg->seg_addr = thisphys;
  442 
  443                                 SC_DEBUGN(sc_link, SDEV_DB4, ("0x%x", thisphys));
  444 
  445                                 /* do it at least once */
  446                                 nextphys = thisphys;
  447                                 while (datalen && thisphys == nextphys) {
  448                                         /*
  449                                          * This page is contiguous (physically)
  450                                          * with the last, just extend the
  451                                          * length
  452                                          */
  453                                         /* how far to the end of the page */
  454                                         nextphys = (thisphys & ~PGOFSET) + NBPG;
  455                                         bytes_this_page = nextphys - thisphys;
  456                                         /**** or the data ****/
  457                                         bytes_this_page = min(bytes_this_page,
  458                                                               datalen);
  459                                         bytes_this_seg += bytes_this_page;
  460                                         datalen -= bytes_this_page;
  461 
  462                                         /* get more ready for the next page */
  463                                         thiskv = (thiskv & ~PGOFSET) + NBPG;
  464                                         if (datalen)
  465                                                 thisphys = KVTOPHYS(thiskv);
  466                                 }
  467                                 /*
  468                                  * next page isn't contiguous, finish the seg
  469                                  */
  470                                 SC_DEBUGN(sc_link, SDEV_DB4,
  471                                     ("(0x%x)", bytes_this_seg));
  472                                 sg->seg_len = bytes_this_seg;
  473                                 sg++;
  474                                 seg++;
  475                         }
  476                 }
  477                 /* end of iov/kv decision */
  478                 SC_DEBUGN(sc_link, SDEV_DB4, ("\n"));
  479                 if (datalen) {
  480                         /*
  481                          * there's still data, must have run out of segs!
  482                          */
  483                         printf("%s: uha_scsi_cmd, more than %d dma segs\n",
  484                             sc->sc_dev.dv_xname, UHA_NSEG);
  485                         goto bad;
  486                 }
  487                 mscp->data_addr = KVTOPHYS(mscp->uha_dma);
  488                 mscp->data_length = xs->datalen;
  489                 mscp->sgth = 0x01;
  490                 mscp->sg_num = seg;
  491         } else {                /* No data xfer, use non S/G values */
  492                 mscp->data_addr = (physaddr)0;
  493                 mscp->data_length = 0;
  494                 mscp->sgth = 0x00;
  495                 mscp->sg_num = 0;
  496         }
  497         mscp->link_id = 0;
  498         mscp->link_addr = (physaddr)0;
  499 
  500         s = splbio();
  501         (sc->start_mbox)(sc, mscp);
  502         splx(s);
  503 
  504         /*
  505          * Usually return SUCCESSFULLY QUEUED
  506          */
  507         if ((flags & SCSI_POLL) == 0)
  508                 return (SUCCESSFULLY_QUEUED);
  509 
  510         /*
  511          * If we can't use interrupts, poll on completion
  512          */
  513         if ((sc->poll)(sc, xs, mscp->timeout)) {
  514                 uha_timeout(mscp);
  515                 if ((sc->poll)(sc, xs, mscp->timeout))
  516                         uha_timeout(mscp);
  517         }
  518         return (COMPLETE);
  519 
  520 bad:
  521         xs->error = XS_DRIVER_STUFFUP;
  522         uha_free_mscp(sc, mscp);
  523         return (COMPLETE);
  524 }
  525 
  526 void
  527 uha_timeout(arg)
  528         void *arg;
  529 {
  530         struct uha_mscp *mscp = arg;
  531         struct scsi_xfer *xs = mscp->xs;
  532         struct scsi_link *sc_link = xs->sc_link;
  533         struct uha_softc *sc = sc_link->adapter_softc;
  534         int s;
  535 
  536         sc_print_addr(sc_link);
  537         printf("timed out");
  538 
  539         s = splbio();
  540 
  541         if (mscp->flags & MSCP_ABORT) {
  542                 /* abort timed out */
  543                 printf(" AGAIN\n");
  544                 /* XXX Must reset! */
  545         } else {
  546                 /* abort the operation that has timed out */
  547                 printf("\n");
  548                 mscp->xs->error = XS_TIMEOUT;
  549                 mscp->timeout = UHA_ABORT_TIMEOUT;
  550                 mscp->flags |= MSCP_ABORT;
  551                 (sc->start_mbox)(sc, mscp);
  552         }
  553 
  554         splx(s);
  555 }

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