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/scsi/scsi_ioctl.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 /*
    2  * Copyright (C) 1992, 1993, 1994, HD Associates, Inc.
    3  * PO Box 276
    4  * Pepperell, MA 01463
    5  * 508 433 5266
    6  * dufault@hda.com
    7  *
    8  * This code is contributed to the University of California at Berkeley:
    9  *
   10  * Redistribution and use in source and binary forms, with or without
   11  * modification, are permitted provided that the following conditions
   12  * are met:
   13  * 1. Redistributions of source code must retain the above copyright
   14  *    notice, this list of conditions and the following disclaimer.
   15  * 2. Redistributions in binary form must reproduce the above copyright
   16  *    notice, this list of conditions and the following disclaimer in the
   17  *    documentation and/or other materials provided with the distribution.
   18  * 3. All advertising materials mentioning features or use of this software
   19  *    must display the following acknowledgement:
   20  *      This product includes software developed by the University of
   21  *      California, Berkeley and its contributors.
   22  * 4. Neither the name of the University nor the names of its contributors
   23  *    may be used to endorse or promote products derived from this software
   24  *    without specific prior written permission.
   25  *
   26  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   27  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   28  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   29  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   30  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   31  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   32  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   33  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   34  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   35  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   36  * SUCH DAMAGE.
   37  *End copyright
   38  *
   39  * $FreeBSD: src/sys/scsi/scsi_ioctl.c,v 1.22.4.1 1999/09/05 08:21:45 peter Exp $
   40  *
   41  *
   42  */
   43 
   44 #include "opt_bounce.h"
   45 #include "opt_scsi.h"
   46 
   47 #include <sys/param.h>
   48 #include <sys/systm.h>
   49 #include <sys/errno.h>
   50 #include <sys/malloc.h>
   51 #include <sys/buf.h>
   52 
   53 #define b_screq b_driver1       /* a patch in buf.h */
   54 #define b_sc_link b_driver2     /* a patch in buf.h */
   55 
   56 #include <sys/fcntl.h>
   57 #include <sys/proc.h>
   58 #include <vm/vm.h>
   59 
   60 #include "scbus.h"
   61 #include <scsi/scsi_all.h>
   62 #include <scsi/scsiconf.h>
   63 #include <sys/scsiio.h>
   64 
   65 static void scsierr(struct buf *, int); /* XXX ??? */
   66 
   67 /*
   68  * We let the user interpret his own sense in the generic scsi world.
   69  * This routine is called at interrupt time if the SCSI_USER bit was set
   70  * in the flags passed to scsi_scsi_cmd(). No other completion processing
   71  * takes place, even if we are running over another device driver.
   72  * The lower level routines that call us here, will free the xs and restart
   73  * the device's queue if such exists.
   74  */
   75 #ifndef min
   76 #define min(A,B) ((A<B) ? A : B )
   77 #endif
   78 
   79 void scsi_user_done(xs)
   80 struct  scsi_xfer *xs;
   81 {
   82 
   83         struct  buf     *bp;
   84         scsireq_t *screq;
   85 
   86         bp = xs->bp;
   87         if(!bp) {       /* ALL user requests must have a buf */
   88                 sc_print_addr(xs->sc_link);
   89                 printf("User command with no buf\n");
   90                 return ;
   91         }
   92         screq = bp->b_screq;
   93         if (!screq) {   /* Is it one of ours? (the SCSI_USER bit says it is) */
   94                 sc_print_addr(xs->sc_link);
   95                 printf("User command with no request\n");
   96                 return ;
   97         }
   98 
   99         SC_DEBUG(xs->sc_link,SDEV_DB2,("user-done\n"));
  100         screq->retsts = 0;
  101         screq->status = xs->status;
  102         switch((int)xs->error) {
  103         case    XS_NOERROR:
  104                 SC_DEBUG(xs->sc_link,SDEV_DB3,("no error\n"));
  105                 if (xs->flags & SCSI_RESID_VALID)
  106                         screq->datalen_used = xs->datalen - xs->resid;
  107                 else
  108                         screq->datalen_used = xs->datalen;
  109                 screq->retsts = SCCMD_OK;
  110                 break;
  111 
  112         case    XS_SENSE:
  113                 SC_DEBUG(xs->sc_link,SDEV_DB3,("have sense\n"));
  114                 screq->senselen_used = min(sizeof(xs->sense),SENSEBUFLEN);
  115                 bcopy(&xs->sense,screq->sense,screq->senselen);
  116                 screq->retsts = SCCMD_SENSE;
  117                 break;
  118 
  119         case    XS_DRIVER_STUFFUP:
  120                 sc_print_addr(xs->sc_link);
  121                 printf("host adapter code inconsistency\n");
  122                 screq->retsts = SCCMD_UNKNOWN;
  123                 break;
  124 
  125         case    XS_TIMEOUT:
  126                 SC_DEBUG(xs->sc_link,SDEV_DB3,("timeout\n"));
  127                 screq->retsts = SCCMD_TIMEOUT;
  128                 break;
  129 
  130         case    XS_BUSY:
  131                 SC_DEBUG(xs->sc_link,SDEV_DB3,("busy\n"));
  132                 screq->retsts = SCCMD_BUSY;
  133                 break;
  134 
  135         default:
  136                 sc_print_addr(xs->sc_link);
  137                 printf("unknown error category from host adapter code\n");
  138                 screq->retsts = SCCMD_UNKNOWN;
  139                 break;
  140         }
  141         biodone(bp);    /* we're waiting on it in scsistrategy() */
  142         return;         /* it'll free the xs and restart any queue */
  143 }
  144 
  145 
  146 /* Pseudo strategy function
  147  * Called by scsi_do_ioctl() via physio/physstrat if there is to
  148  * be data transfered, and directly if there is no data transfer.
  149  *
  150  * Can't be used with block devices or raw_read/raw_write directly
  151  * from the cdevsw/bdevsw tables because they couldn't have added
  152  * the screq structure. [JRE]
  153  */
  154 static void 
  155 scsistrategy(struct buf *bp)
  156 {
  157         errval err;
  158         struct  scsi_link *sc_link = bp->b_sc_link;
  159         scsireq_t *screq;
  160         u_int32_t flags = 0;
  161         int s;
  162 
  163 
  164         if(!sc_link) {
  165                 printf("user_strat: No link pointer\n");
  166                 scsierr(bp,EINVAL);
  167                 return;
  168         }
  169         SC_DEBUG(sc_link,SDEV_DB2,("user_strategy\n"));
  170         screq = bp->b_screq;
  171         if(!screq) {
  172                 sc_print_addr(sc_link);
  173                 printf("No request block\n");
  174                 scsierr(bp,EINVAL);
  175                 return;
  176         }
  177 
  178         /* We're in trouble if physio tried to break up the
  179          * transfer:
  180          */
  181         if (bp->b_bcount != screq->datalen) {
  182                 sc_print_addr(sc_link);
  183                 printf("physio split the request.. cannot proceed\n");
  184                 scsierr(bp, EIO);
  185                 return;
  186         }
  187 
  188         if (screq->timeout == 0) {
  189                 scsierr(bp, EINVAL);
  190                 return;
  191         }
  192 
  193         if (screq->cmdlen > sizeof(struct scsi_generic)) {
  194                 sc_print_addr(sc_link);
  195                 printf("cmdlen too big ");
  196                 scsierr(bp, EFAULT);
  197                 return;
  198         }
  199 
  200 
  201         if (screq->flags & SCCMD_READ)
  202                 flags |= SCSI_DATA_IN;
  203 
  204         if (screq->flags & SCCMD_WRITE)
  205                 flags |= SCSI_DATA_OUT;
  206 
  207         if (screq->flags & SCCMD_TARGET)
  208                 flags |= SCSI_TARGET;
  209 
  210         if (screq->flags & SCCMD_ESCAPE)
  211                 flags |= SCSI_ESCAPE;
  212 
  213 #ifdef BOUNCE_BUFFERS
  214         if (sc_link->flags & SDEV_BOUNCE)
  215                 vm_bounce_alloc(bp);
  216 #endif
  217 
  218         err = scsi_scsi_cmd(sc_link,
  219                         (struct scsi_generic *)screq->cmd,
  220                         screq->cmdlen,
  221                         (u_char *)bp->b_un.b_addr,
  222                         screq->datalen,
  223                         0,      /* user must do the retries *//* ignored */
  224                         screq->timeout,
  225                         bp,
  226                         flags | SCSI_USER);
  227 
  228 
  229 
  230         /*because there is a bp, scsi_scsi_cmd will return immediatly*/
  231         if (err)
  232         {
  233                 scsierr(bp, err);
  234                 return;
  235         }
  236         SC_DEBUG(sc_link,SDEV_DB3,("about to  sleep\n"));
  237         s = splbio();
  238         while(!(bp->b_flags & B_DONE))
  239         {
  240                 tsleep((caddr_t)bp, PRIBIO, "scsistrat", 0);
  241         }
  242         splx(s);
  243         SC_DEBUG(sc_link,SDEV_DB3,("back from sleep\n"));
  244         return;
  245 }
  246 
  247 /*
  248  * Something (e.g. another driver) has called us
  249  * with an sc_link for a target/lun/adapter, and a scsi
  250  * specific ioctl to perform, better try.
  251  * If user-level type command, we must still be running
  252  * in the context of the calling process
  253  */
  254 errval  scsi_do_ioctl(dev_t dev, int cmd, caddr_t addr, int flags,
  255 struct proc *p, struct scsi_link *sc_link)
  256 {
  257         errval ret = 0;
  258 
  259         /* If we can't write the device we can't permit much:
  260          */
  261 
  262         if (cmd != SCIOCIDENTIFY && !(flags & FWRITE))
  263                 return EACCES;
  264 
  265         SC_DEBUG(sc_link,SDEV_DB2,("scsi_do_ioctl(0x%x)\n",cmd));
  266         switch(cmd)
  267         {
  268                 case SCIOCCOMMAND:
  269                 {
  270                         /*
  271                          * You won't believe this, but the arg copied in
  272                          * from the user space, is on the kernel stack
  273                          * for this process, so we can't write
  274                          * to it at interrupt time..
  275                          * we need to copy it in and out!
  276                          * Make a static copy using malloc!
  277                          */
  278                         scsireq_t *screq2 = (scsireq_t *)addr;
  279                         scsireq_t *screq = (scsireq_t *)addr;
  280                         int rwflag = (screq->flags & SCCMD_READ) ? B_READ : B_WRITE;
  281                         struct buf *bp;
  282                         caddr_t d_addr;
  283                         int     len;
  284 
  285 #if 0   /* XXX dufault@hda.com: This looks too rev dependent.  Do it always? */
  286                         if((unsigned int)screq < (unsigned int)KERNBASE)
  287 #endif
  288                         {
  289                                 screq = malloc(sizeof(scsireq_t),M_TEMP,M_WAITOK);
  290                                 bcopy(screq2,screq,sizeof(scsireq_t));
  291                         }
  292                         bp = malloc(sizeof (struct buf),M_TEMP,M_WAITOK);
  293                         bzero(bp,sizeof(struct buf));
  294                         d_addr = screq->databuf;
  295                         bp->b_bcount = len = screq->datalen;
  296                         bp->b_screq = screq;
  297                         bp->b_sc_link = sc_link;
  298                         if (len) {
  299                                 struct uio auio;
  300                                 struct iovec aiov;
  301                                 long cnt;
  302 
  303                                 aiov.iov_base = d_addr;
  304                                 aiov.iov_len = len;
  305                                 auio.uio_iov = &aiov;
  306                                 auio.uio_iovcnt = 1;
  307 
  308                                 auio.uio_resid = len;
  309                                 if (auio.uio_resid < 0)
  310                                         return (EINVAL);
  311 
  312                                 auio.uio_rw = (rwflag == B_READ)  ? UIO_READ : UIO_WRITE;
  313                                 auio.uio_segflg = UIO_USERSPACE;
  314                                 auio.uio_procp = curproc;
  315                                 cnt = len;
  316                                 ret = physio(scsistrategy, bp, dev, rwflag,
  317                                         minphys, &auio);
  318                         } else {
  319                                 /* if no data, no need to translate it.. */
  320                                 bp->b_un.b_addr = 0;
  321                                 bp->b_dev = dev;
  322                                 bp->b_flags |= B_BUSY;
  323 
  324                                 scsistrategy(bp);
  325                                 ret =  bp->b_error;
  326                         }
  327                         free(bp,M_TEMP);
  328 #if 0   /* XXX dufault@hda.com: This looks too rev dependent.  Do it always? */
  329                         if((unsigned int)screq2 < (unsigned int)KERNBASE)
  330 #endif
  331                         {
  332                                 bcopy(screq,screq2,sizeof(scsireq_t));
  333                                 free(screq,M_TEMP);
  334                         }
  335                         break;
  336                 }
  337                 case SCIOCDEBUG:
  338                 {
  339                         int level = *((int *)addr);
  340                         SC_DEBUG(sc_link,SDEV_DB3,("debug set to %d\n",level));
  341                         sc_link->flags &= ~SDEV_DBX; /*clear debug bits */
  342                         if(level & 1) sc_link->flags |= SDEV_DB1;
  343                         if(level & 2) sc_link->flags |= SDEV_DB2;
  344                         if(level & 4) sc_link->flags |= SDEV_DB3;
  345                         if(level & 8) sc_link->flags |= SDEV_DB4;
  346                         ret = 0;
  347                         break;
  348                 }
  349                 case SCIOCREPROBE:
  350                 {
  351                         struct scsi_addr *sca = (struct scsi_addr *) addr;
  352 
  353                         ret = scsi_probe_busses(sca->scbus,sca->target,sca->lun);
  354                         break;
  355                 }
  356                 case SCIOCRECONFIG:
  357                 case SCIOCDECONFIG:
  358                         ret = EINVAL;
  359                         break;
  360 
  361                 case SCIOCIDENTIFY:
  362                 {
  363                         struct scsi_addr *sca = (struct scsi_addr *) addr;
  364                         sca->scbus      = sc_link->scsibus;
  365                         sca->target     = sc_link->target;
  366                         sca->lun        = sc_link->lun;
  367                         break;
  368                 }
  369 
  370                 default:
  371                         ret = ENOTTY;
  372                 break;
  373         }
  374 
  375         return ret;
  376 }
  377 
  378 void
  379 scsierr(bp,err)
  380         struct buf *bp;
  381         int     err;
  382 {
  383                 bp->b_flags |= B_ERROR;
  384                 bp->b_error = err;
  385                 biodone(bp);
  386                 return;
  387 }
  388 

Cache object: d18da179019b9e587a5aeb535e936f2e


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