root/scsi/scsi_ioctl.c

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

DEFINITIONS

This source file includes following definitions.
  1. si_get
  2. si_free
  3. si_find
  4. scsi_user_done
  5. scsistrategy
  6. scsi_do_ioctl

    1 /*      $OpenBSD: scsi_ioctl.c,v 1.28 2007/01/16 00:43:19 krw Exp $     */
    2 /*      $NetBSD: scsi_ioctl.c,v 1.23 1996/10/12 23:23:17 christos Exp $ */
    3 
    4 /*
    5  * Copyright (c) 1994 Charles Hannum.  All rights reserved.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  * 1. Redistributions of source code must retain the above copyright
   11  *    notice, this list of conditions and the following disclaimer.
   12  * 2. Redistributions in binary form must reproduce the above copyright
   13  *    notice, this list of conditions and the following disclaimer in the
   14  *    documentation and/or other materials provided with the distribution.
   15  * 3. All advertising materials mentioning features or use of this software
   16  *    must display the following acknowledgement:
   17  *      This product includes software developed by Charles Hannum.
   18  * 4. The name of the author may not be used to endorse or promote products
   19  *    derived from this software without specific prior written permission.
   20  *
   21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   22  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   23  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   24  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   26  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   30  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   31  */
   32 
   33 /*
   34  * Contributed by HD Associates (hd@world.std.com).
   35  * Copyright (c) 1992, 1993 HD Associates
   36  *
   37  * Berkeley style copyright.
   38  */
   39 
   40 #include <sys/types.h>
   41 #include <sys/errno.h>
   42 #include <sys/param.h>
   43 #include <sys/systm.h>
   44 #include <sys/file.h>
   45 #include <sys/malloc.h>
   46 #include <sys/buf.h>
   47 #include <sys/proc.h>
   48 #include <sys/device.h>
   49 #include <sys/fcntl.h>
   50 
   51 #include <scsi/scsi_all.h>
   52 #include <scsi/scsiconf.h>
   53 #include <sys/scsiio.h>
   54 
   55 struct scsi_ioctl {
   56         LIST_ENTRY(scsi_ioctl)  si_list;
   57         struct buf              si_bp;
   58         struct uio              si_uio;
   59         struct iovec            si_iov;
   60         scsireq_t               si_screq;
   61         struct scsi_link        *si_sc_link;
   62 };
   63 
   64 LIST_HEAD(, scsi_ioctl)         si_head;
   65 
   66 struct scsi_ioctl       *si_get(void);
   67 void                    si_free(struct scsi_ioctl *);
   68 struct scsi_ioctl       *si_find(struct buf *);
   69 void                    scsistrategy(struct buf *);
   70 
   71 const unsigned char scsi_readsafe_cmd[256] = {
   72         [0x00] = 1,     /* TEST UNIT READY */
   73         [0x03] = 1,     /* REQUEST SENSE */
   74         [0x08] = 1,     /* READ(6) */
   75         [0x12] = 1,     /* INQUIRY */
   76         [0x1a] = 1,     /* MODE SENSE */
   77         [0x1b] = 1,     /* START STOP */
   78         [0x23] = 1,     /* READ FORMAT CAPACITIES */
   79         [0x25] = 1,     /* READ CDVD CAPACITY */
   80         [0x28] = 1,     /* READ(10) */
   81         [0x2b] = 1,     /* SEEK */
   82         [0x2f] = 1,     /* VERIFY(10) */
   83         [0x3c] = 1,     /* READ BUFFER */
   84         [0x3e] = 1,     /* READ LONG */
   85         [0x42] = 1,     /* READ SUBCHANNEL */
   86         [0x43] = 1,     /* READ TOC PMA ATIP */
   87         [0x44] = 1,     /* READ HEADER */
   88         [0x45] = 1,     /* PLAY AUDIO(10) */
   89         [0x46] = 1,     /* GET CONFIGURATION */
   90         [0x47] = 1,     /* PLAY AUDIO MSF */
   91         [0x48] = 1,     /* PLAY AUDIO TI */
   92         [0x4a] = 1,     /* GET EVENT STATUS NOTIFICATION */
   93         [0x4b] = 1,     /* PAUSE RESUME */
   94         [0x4e] = 1,     /* STOP PLAY SCAN */
   95         [0x51] = 1,     /* READ DISC INFO */
   96         [0x52] = 1,     /* READ TRACK RZONE INFO */
   97         [0x5a] = 1,     /* MODE SENSE(10) */
   98         [0x88] = 1,     /* READ(16) */
   99         [0x8f] = 1,     /* VERIFY(16) */
  100         [0xa4] = 1,     /* REPORT KEY */
  101         [0xa5] = 1,     /* PLAY AUDIO(12) */
  102         [0xa8] = 1,     /* READ(12) */
  103         [0xac] = 1,     /* GET PERFORMANCE */
  104         [0xad] = 1,     /* READ DVD STRUCTURE */
  105         [0xb9] = 1,     /* READ CD MSF */
  106         [0xba] = 1,     /* SCAN */
  107         [0xbc] = 1,     /* PLAY CD */
  108         [0xbd] = 1,     /* MECHANISM STATUS */
  109         [0xbe] = 1      /* READ CD */
  110 };
  111 
  112 struct scsi_ioctl *
  113 si_get(void)
  114 {
  115         struct scsi_ioctl                       *si;
  116         int                                     s;
  117 
  118         si = malloc(sizeof(struct scsi_ioctl), M_TEMP, M_WAITOK);
  119         bzero(si, sizeof(struct scsi_ioctl));
  120         s = splbio();
  121         LIST_INSERT_HEAD(&si_head, si, si_list);
  122         splx(s);
  123         return (si);
  124 }
  125 
  126 void
  127 si_free(struct scsi_ioctl *si)
  128 {
  129         int                                     s;
  130 
  131         s = splbio();
  132         LIST_REMOVE(si, si_list);
  133         splx(s);
  134         free(si, M_TEMP);
  135 }
  136 
  137 struct scsi_ioctl *
  138 si_find(struct buf *bp)
  139 {
  140         struct scsi_ioctl                       *si;
  141         int                                     s;
  142 
  143         s = splbio();
  144         LIST_FOREACH(si, &si_head, si_list) {
  145                 if (bp == &si->si_bp)
  146                         break;
  147         }
  148         splx(s);
  149 
  150         return (si);
  151 }
  152 
  153 /*
  154  * We let the user interpret his own sense in the generic scsi world.
  155  * This routine is called at interrupt time if the SCSI_USER bit was set
  156  * in the flags passed to scsi_scsi_cmd(). No other completion processing
  157  * takes place, even if we are running over another device driver.
  158  * The lower level routines that call us here, will free the xs and restart
  159  * the device's queue if such exists.
  160  */
  161 void
  162 scsi_user_done(struct scsi_xfer *xs)
  163 {
  164         struct buf                              *bp;
  165         struct scsi_ioctl                       *si;
  166         scsireq_t                               *screq;
  167         struct scsi_link                        *sc_link;
  168 
  169         splassert(IPL_BIO);
  170 
  171         bp = xs->bp;
  172         if (bp == NULL) {       /* ALL user requests must have a buf */
  173                 sc_print_addr(xs->sc_link);
  174                 printf("User command with no buf\n");
  175                 return;
  176         }
  177 
  178         si = si_find(bp);
  179         if (si == NULL) {
  180                 sc_print_addr(xs->sc_link);
  181                 printf("User command with no ioctl\n");
  182                 return;
  183         }
  184 
  185         screq = &si->si_screq;
  186         sc_link = si->si_sc_link;
  187         SC_DEBUG(xs->sc_link, SDEV_DB2, ("user-done\n"));
  188 
  189         screq->retsts = 0;
  190         screq->status = xs->status;
  191         switch (xs->error) {
  192         case XS_NOERROR:
  193                 SC_DEBUG(sc_link, SDEV_DB3, ("no error\n"));
  194                 /* probably rubbish */
  195                 screq->datalen_used = xs->datalen - xs->resid;
  196                 screq->retsts = SCCMD_OK;
  197                 break;
  198         case XS_SENSE:
  199                 SC_DEBUG(sc_link, SDEV_DB3, ("have sense\n"));
  200                 screq->senselen_used = min(sizeof(xs->sense), SENSEBUFLEN);
  201                 bcopy(&xs->sense, screq->sense, screq->senselen);
  202                 screq->retsts = SCCMD_SENSE;
  203                 break;
  204         case XS_SHORTSENSE:
  205                 SC_DEBUG(sc_link, SDEV_DB3, ("have short sense\n"));
  206                 screq->senselen_used = min(sizeof(xs->sense), SENSEBUFLEN);
  207                 bcopy(&xs->sense, screq->sense, screq->senselen);
  208                 screq->retsts = SCCMD_UNKNOWN;
  209                 break;
  210         case XS_DRIVER_STUFFUP:
  211                 sc_print_addr(sc_link);
  212                 printf("host adapter code inconsistency\n");
  213                 screq->retsts = SCCMD_UNKNOWN;
  214                 break;
  215         case XS_TIMEOUT:
  216                 SC_DEBUG(sc_link, SDEV_DB3, ("timeout\n"));
  217                 screq->retsts = SCCMD_TIMEOUT;
  218                 break;
  219         case XS_BUSY:
  220                 SC_DEBUG(sc_link, SDEV_DB3, ("busy\n"));
  221                 screq->retsts = SCCMD_BUSY;
  222                 break;
  223         default:
  224                 sc_print_addr(sc_link);
  225                 printf("unknown error category (0x%x) from host adapter code\n",
  226                     xs->error);
  227                 screq->retsts = SCCMD_UNKNOWN;
  228                 break;
  229         }
  230 
  231         biodone(bp);    /* we're waiting on it in scsi_strategy() */
  232 }
  233 
  234 
  235 /* Pseudo strategy function
  236  * Called by scsi_do_ioctl() via physio/physstrat if there is to
  237  * be data transferred, and directly if there is no data transfer.
  238  * 
  239  * Should I reorganize this so it returns to physio instead
  240  * of sleeping in scsiio_scsi_cmd?  Is there any advantage, other
  241  * than avoiding the probable duplicate wakeup in iodone? [PD]
  242  *
  243  * No, seems ok to me... [JRE]
  244  * (I don't see any duplicate wakeups)
  245  *
  246  * Can't be used with block devices or raw_read/raw_write directly
  247  * from the cdevsw/bdevsw tables because they couldn't have added
  248  * the screq structure. [JRE]
  249  */
  250 void
  251 scsistrategy(struct buf *bp)
  252 {
  253         struct scsi_ioctl                       *si;
  254         scsireq_t                               *screq;
  255         struct scsi_link                        *sc_link;
  256         int                                     error;
  257         int                                     flags = 0;
  258         int                                     s;
  259 
  260         si = si_find(bp);
  261         if (si == NULL) {
  262                 printf("user_strat: No ioctl\n");
  263                 error = EINVAL;
  264                 goto bad;
  265         }
  266 
  267         screq = &si->si_screq;
  268         sc_link = si->si_sc_link;
  269         SC_DEBUG(sc_link, SDEV_DB2, ("user_strategy\n"));
  270 
  271         /*
  272          * We're in trouble if physio tried to break up the transfer.
  273          */
  274         if (bp->b_bcount != screq->datalen) {
  275                 sc_print_addr(sc_link);
  276                 printf("physio split the request.. cannot proceed\n");
  277                 error = EIO;
  278                 goto bad;
  279         }
  280 
  281         if (screq->timeout == 0) {
  282                 error = EINVAL;
  283                 goto bad;
  284         }
  285 
  286         if (screq->cmdlen > sizeof(struct scsi_generic)) {
  287                 sc_print_addr(sc_link);
  288                 printf("cmdlen too big\n");
  289                 error = EFAULT;
  290                 goto bad;
  291         }
  292 
  293         if (screq->flags & SCCMD_READ)
  294                 flags |= SCSI_DATA_IN;
  295         if (screq->flags & SCCMD_WRITE)
  296                 flags |= SCSI_DATA_OUT;
  297         if (screq->flags & SCCMD_TARGET)
  298                 flags |= SCSI_TARGET;
  299         if (screq->flags & SCCMD_ESCAPE)
  300                 flags |= SCSI_ESCAPE;
  301 
  302         error = scsi_scsi_cmd(sc_link, (struct scsi_generic *)screq->cmd,
  303             screq->cmdlen, (u_char *)bp->b_data, screq->datalen,
  304             0, /* user must do the retries *//* ignored */
  305             screq->timeout, bp, flags | SCSI_USER | SCSI_NOSLEEP);
  306 
  307         /* because there is a bp, scsi_scsi_cmd will return immediately */
  308         if (error)
  309                 goto bad;
  310 
  311         SC_DEBUG(sc_link, SDEV_DB3, ("about to sleep\n"));
  312         s = splbio();
  313         while ((bp->b_flags & B_DONE) == 0)
  314                 tsleep(bp, PRIBIO, "scistr", 0);
  315         splx(s);
  316         SC_DEBUG(sc_link, SDEV_DB3, ("back from sleep\n"));
  317 
  318         return;
  319 
  320 bad:
  321         bp->b_flags |= B_ERROR;
  322         bp->b_error = error;
  323         s = splbio();
  324         biodone(bp);
  325         splx(s);
  326 }
  327 
  328 /*
  329  * Something (e.g. another driver) has called us
  330  * with an sc_link for a target/lun/adapter, and a scsi
  331  * specific ioctl to perform, better try.
  332  * If user-level type command, we must still be running
  333  * in the context of the calling process
  334  */
  335 int
  336 scsi_do_ioctl(struct scsi_link *sc_link, dev_t dev, u_long cmd, caddr_t addr,
  337     int flag, struct proc *p)
  338 {
  339         int                                     error;
  340 
  341         SC_DEBUG(sc_link, SDEV_DB2, ("scsi_do_ioctl(0x%lx)\n", cmd));
  342 
  343         switch(cmd) {
  344         case SCIOCIDENTIFY: {
  345                 struct scsi_addr *sca = (struct scsi_addr *)addr;
  346 
  347                 if ((sc_link->flags & (SDEV_ATAPI | SDEV_UMASS)) == 0)
  348                         /* A 'real' SCSI target. */
  349                         sca->type = TYPE_SCSI;
  350                 else    
  351                         /* An 'emulated' SCSI target. */
  352                         sca->type = TYPE_ATAPI;
  353                 sca->scbus = sc_link->scsibus;
  354                 sca->target = sc_link->target;
  355                 sca->lun = sc_link->lun;
  356                 return (0);
  357         }
  358         case SCIOCCOMMAND:
  359                 if (scsi_readsafe_cmd[((scsireq_t *)addr)->cmd[0]])
  360                         break;
  361                 /* FALLTHROUGH */
  362         case SCIOCDEBUG:
  363         case SCIOCRESET:
  364                 if ((flag & FWRITE) == 0)
  365                         return (EPERM);
  366                 break;
  367         default:
  368                 if (sc_link->adapter->ioctl)
  369                         return ((sc_link->adapter->ioctl)(sc_link, cmd, addr,
  370                             flag, p));
  371                 else
  372                         return (ENOTTY);
  373         }
  374 
  375         switch(cmd) {
  376         case SCIOCCOMMAND: {
  377                 scsireq_t *screq = (scsireq_t *)addr;
  378                 struct scsi_ioctl *si;
  379 
  380                 si = si_get();
  381                 si->si_screq = *screq;
  382                 si->si_sc_link = sc_link;
  383                 if (screq->datalen) {
  384                         si->si_iov.iov_base = screq->databuf;
  385                         si->si_iov.iov_len = screq->datalen;
  386                         si->si_uio.uio_iov = &si->si_iov;
  387                         si->si_uio.uio_iovcnt = 1;
  388                         si->si_uio.uio_resid = screq->datalen;
  389                         si->si_uio.uio_offset = 0;
  390                         si->si_uio.uio_segflg = UIO_USERSPACE;
  391                         si->si_uio.uio_rw =
  392                             (screq->flags & SCCMD_READ) ? UIO_READ : UIO_WRITE;
  393                         si->si_uio.uio_procp = p;
  394                         error = physio(scsistrategy, &si->si_bp, dev,
  395                             (screq->flags & SCCMD_READ) ? B_READ : B_WRITE,
  396                             sc_link->adapter->scsi_minphys, &si->si_uio);
  397                 } else {
  398                         /* if no data, no need to translate it.. */
  399                         si->si_bp.b_flags = 0;
  400                         si->si_bp.b_data = 0;
  401                         si->si_bp.b_bcount = 0;
  402                         si->si_bp.b_dev = dev;
  403                         si->si_bp.b_proc = p;
  404                         scsistrategy(&si->si_bp);
  405                         error = si->si_bp.b_error;
  406                 }
  407                 *screq = si->si_screq;
  408                 si_free(si);
  409                 return (error);
  410         }
  411         case SCIOCDEBUG: {
  412                 int level = *((int *)addr);
  413 
  414                 SC_DEBUG(sc_link, SDEV_DB3, ("debug set to %d\n", level));
  415                 sc_link->flags &= ~SDEV_DBX; /* clear debug bits */
  416                 if (level & 1)
  417                         sc_link->flags |= SDEV_DB1;
  418                 if (level & 2)
  419                         sc_link->flags |= SDEV_DB2;
  420                 if (level & 4)
  421                         sc_link->flags |= SDEV_DB3;
  422                 if (level & 8)
  423                         sc_link->flags |= SDEV_DB4;
  424                 return (0);
  425         }
  426         case SCIOCRESET: {
  427                 scsi_scsi_cmd(sc_link, 0, 0, 0, 0, GENRETRY, 2000, NULL,
  428                     SCSI_RESET);
  429                 return (0);
  430         }
  431         default:
  432 #ifdef DIAGNOSTIC
  433                 panic("scsi_do_ioctl: impossible cmd (%#lx)", cmd);
  434 #endif
  435                 return (0);
  436         }
  437 }

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