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/scsipi/st_scsi.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 /*      $NetBSD: st_scsi.c,v 1.10.8.1 2004/09/11 12:59:02 he Exp $ */
    2 
    3 /*-
    4  * Copyright (c) 1998 The NetBSD Foundation, Inc.
    5  * All rights reserved.
    6  *
    7  * This code is derived from software contributed to The NetBSD Foundation
    8  * by Charles M. Hannum.
    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 NetBSD
   21  *        Foundation, Inc. and its contributors.
   22  * 4. Neither the name of The NetBSD Foundation nor the names of its
   23  *    contributors may be used to endorse or promote products derived
   24  *    from this software without specific prior written permission.
   25  *
   26  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
   27  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   28  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   29  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
   30  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   36  * POSSIBILITY OF SUCH DAMAGE.
   37  */
   38 
   39 /*
   40  * Originally written by Julian Elischer (julian@tfs.com)
   41  * for TRW Financial Systems for use under the MACH(2.5) operating system.
   42  *
   43  * TRW Financial Systems, in accordance with their agreement with Carnegie
   44  * Mellon University, makes this software available to CMU to distribute
   45  * or use in any manner that they see fit as long as this message is kept with
   46  * the software. For this reason TFS also grants any other persons or
   47  * organisations permission to use or modify this software.
   48  *
   49  * TFS supplies this software to be publicly redistributed
   50  * on the understanding that TFS is not responsible for the correct
   51  * functioning of this software in any circumstances.
   52  *
   53  * Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992
   54  * major changes by Julian Elischer (julian@jules.dialix.oz.au) May 1993
   55  *
   56  * A lot of rewhacking done by mjacob (mjacob@nas.nasa.gov).
   57  */
   58 
   59 #include <sys/cdefs.h>
   60 __KERNEL_RCSID(0, "$NetBSD: st_scsi.c,v 1.10.8.1 2004/09/11 12:59:02 he Exp $");
   61 
   62 #include "opt_scsi.h"
   63 #include "rnd.h"
   64 
   65 #include <sys/param.h>
   66 #include <sys/device.h>
   67 #include <sys/buf.h>
   68 #include <sys/conf.h>
   69 #include <sys/kernel.h>
   70 #include <sys/systm.h>
   71 
   72 #include <dev/scsipi/stvar.h>
   73 #include <dev/scsipi/scsi_tape.h>
   74 #include <dev/scsipi/scsi_all.h>
   75 
   76 int     st_scsibus_match __P((struct device *, struct cfdata *, void *));
   77 void    st_scsibus_attach __P((struct device *, struct device *, void *));
   78 int     st_scsibus_ops __P((struct st_softc *, int, int));
   79 int     st_scsibus_read_block_limits __P((struct st_softc *, int));
   80 int     st_scsibus_mode_sense __P((struct st_softc *, int));
   81 int     st_scsibus_mode_select __P((struct st_softc *, int));
   82 int     st_scsibus_cmprss __P((struct st_softc *, int, int));
   83 
   84 CFATTACH_DECL(st_scsibus, sizeof(struct st_softc),
   85     st_scsibus_match, st_scsibus_attach, stdetach, stactivate);
   86 
   87 const struct scsipi_inquiry_pattern st_scsibus_patterns[] = {
   88         {T_SEQUENTIAL, T_REMOV,
   89          "",         "",                 ""},
   90 };
   91 
   92 int
   93 st_scsibus_match(parent, match, aux)
   94         struct device *parent;
   95         struct cfdata *match;
   96         void *aux;
   97 {
   98         struct scsipibus_attach_args *sa = aux;
   99         int priority;
  100 
  101         if (scsipi_periph_bustype(sa->sa_periph) != SCSIPI_BUSTYPE_SCSI)
  102                 return (0);
  103 
  104         (void)scsipi_inqmatch(&sa->sa_inqbuf,
  105             (caddr_t)st_scsibus_patterns,
  106             sizeof(st_scsibus_patterns)/sizeof(st_scsibus_patterns[0]),
  107             sizeof(st_scsibus_patterns[0]), &priority);
  108         return (priority);
  109 }
  110 
  111 void
  112 st_scsibus_attach(parent, self, aux)
  113         struct device *parent, *self;
  114         void *aux;
  115 {
  116         struct st_softc *st = (void *)self;
  117 
  118         st->ops = st_scsibus_ops;
  119         stattach(parent, st, aux);
  120 }
  121 
  122 int
  123 st_scsibus_ops(st, op, flags)
  124         struct st_softc *st;
  125         int op;
  126         int flags;
  127 {
  128         switch(op) {
  129         case ST_OPS_RBL:
  130                 return st_scsibus_read_block_limits(st, flags);
  131         case ST_OPS_MODESENSE:
  132                 return st_scsibus_mode_sense(st, flags);
  133         case ST_OPS_MODESELECT:
  134                 return st_scsibus_mode_select(st, flags);
  135         case ST_OPS_CMPRSS_ON:
  136         case ST_OPS_CMPRSS_OFF:
  137                 return st_scsibus_cmprss(st, flags,
  138                     (op == ST_OPS_CMPRSS_ON) ? 1 : 0);
  139         default:
  140                 panic("st_scsibus_ops: invalid op");
  141                 return 0; /* XXX to appease gcc */
  142         }
  143         /* NOTREACHED */
  144 }
  145 
  146 /*
  147  * Ask the drive what it's min and max blk sizes are.
  148  */
  149 int
  150 st_scsibus_read_block_limits(st, flags)
  151         struct st_softc *st;
  152         int flags;
  153 {
  154         struct scsi_block_limits cmd;
  155         struct scsi_block_limits_data block_limits;
  156         struct scsipi_periph *periph = st->sc_periph;
  157         int error;
  158 
  159         /*
  160          * do a 'Read Block Limits'
  161          */
  162         memset(&cmd, 0, sizeof(cmd));
  163         cmd.opcode = READ_BLOCK_LIMITS;
  164 
  165         /*
  166          * do the command, update the global values
  167          */
  168         error = scsipi_command(periph, NULL, (struct scsipi_generic *)&cmd,
  169             sizeof(cmd), (u_char *)&block_limits, sizeof(block_limits),
  170             ST_RETRIES, ST_CTL_TIME, NULL,
  171             flags | XS_CTL_DATA_IN | XS_CTL_DATA_ONSTACK);
  172         if (error)
  173                 return (error);
  174 
  175         st->blkmin = _2btol(block_limits.min_length);
  176         st->blkmax = _3btol(block_limits.max_length);
  177 
  178         SC_DEBUG(periph, SCSIPI_DB3,
  179             ("(%d <= blksize <= %d)\n", st->blkmin, st->blkmax));
  180         return (0);
  181 }
  182 
  183 /*
  184  * Get the scsi driver to send a full inquiry to the
  185  * device and use the results to fill out the global
  186  * parameter structure.
  187  *
  188  * called from:
  189  * attach
  190  * open
  191  * ioctl (to reset original blksize)
  192  */
  193 int
  194 st_scsibus_mode_sense(st, flags)
  195         struct st_softc *st;
  196         int flags;
  197 {
  198         u_int scsipi_sense_len;
  199         int error;
  200         struct scsipi_sense {
  201                 struct scsipi_mode_header header;
  202                 struct scsi_blk_desc blk_desc;
  203                 u_char sense_data[MAX_PAGE_0_SIZE];
  204         } scsipi_sense;
  205         struct scsipi_periph *periph = st->sc_periph;
  206 
  207         scsipi_sense_len = 12 + st->page_0_size;
  208 
  209         /*
  210          * Set up a mode sense
  211          * We don't need the results. Just print them for our interest's sake,
  212          * if asked, or if we need it as a template for the mode select store
  213          * it away.
  214          */
  215         error = scsipi_mode_sense(st->sc_periph, 0, SMS_PAGE_CTRL_CURRENT,
  216             &scsipi_sense.header, scsipi_sense_len, flags | XS_CTL_DATA_ONSTACK,
  217             ST_RETRIES, ST_CTL_TIME);
  218         if (error)
  219                 return (error);
  220 
  221         st->numblks = _3btol(scsipi_sense.blk_desc.nblocks);
  222         st->media_blksize = _3btol(scsipi_sense.blk_desc.blklen);
  223         st->media_density = scsipi_sense.blk_desc.density;
  224         if (scsipi_sense.header.dev_spec & SMH_DSP_WRITE_PROT)
  225                 st->flags |= ST_READONLY;
  226         else
  227                 st->flags &= ~ST_READONLY;
  228         SC_DEBUG(periph, SCSIPI_DB3,
  229             ("density code %d, %d-byte blocks, write-%s, ",
  230             st->media_density, st->media_blksize,
  231             st->flags & ST_READONLY ? "protected" : "enabled"));
  232         SC_DEBUG(periph, SCSIPI_DB3,
  233             ("%sbuffered\n",
  234             scsipi_sense.header.dev_spec & SMH_DSP_BUFF_MODE ? "" : "un"));
  235         if (st->page_0_size)
  236                 memcpy(st->sense_data, scsipi_sense.sense_data,
  237                     st->page_0_size);
  238         periph->periph_flags |= PERIPH_MEDIA_LOADED;
  239         return (0);
  240 }
  241 
  242 /*
  243  * Send a filled out parameter structure to the drive to
  244  * set it into the desire modes etc.
  245  */
  246 int
  247 st_scsibus_mode_select(st, flags)
  248         struct st_softc *st;
  249         int flags;
  250 {
  251         u_int scsi_select_len;
  252         struct scsi_select {
  253                 struct scsipi_mode_header header;
  254                 struct scsi_blk_desc blk_desc;
  255                 u_char sense_data[MAX_PAGE_0_SIZE];
  256         } scsi_select;
  257         struct scsipi_periph *periph = st->sc_periph;
  258 
  259         scsi_select_len = 12 + st->page_0_size;
  260 
  261         /*
  262          * This quirk deals with drives that have only one valid mode
  263          * and think this gives them license to reject all mode selects,
  264          * even if the selected mode is the one that is supported.
  265          */
  266         if (st->quirks & ST_Q_UNIMODAL) {
  267                 SC_DEBUG(periph, SCSIPI_DB3,
  268                     ("not setting density 0x%x blksize 0x%x\n",
  269                     st->density, st->blksize));
  270                 return (0);
  271         }
  272 
  273         /*
  274          * Set up for a mode select
  275          */
  276         memset(&scsi_select, 0, scsi_select_len);
  277         scsi_select.header.blk_desc_len = sizeof(struct scsi_blk_desc);
  278         scsi_select.header.dev_spec &= ~SMH_DSP_BUFF_MODE;
  279         scsi_select.blk_desc.density = st->density;
  280         if (st->flags & ST_DONTBUFFER)
  281                 scsi_select.header.dev_spec |= SMH_DSP_BUFF_MODE_OFF;
  282         else
  283                 scsi_select.header.dev_spec |= SMH_DSP_BUFF_MODE_ON;
  284         if (st->flags & ST_FIXEDBLOCKS)
  285                 _lto3b(st->blksize, scsi_select.blk_desc.blklen);
  286         if (st->page_0_size)
  287                 memcpy(scsi_select.sense_data, st->sense_data, st->page_0_size);
  288 
  289         /*
  290          * do the command
  291          */
  292         return scsipi_mode_select(periph, 0, &scsi_select.header, 
  293             scsi_select_len, flags | XS_CTL_DATA_ONSTACK,
  294             ST_RETRIES, ST_CTL_TIME);
  295 }
  296 
  297 int
  298 st_scsibus_cmprss(st, flags, onoff)
  299         struct st_softc *st;
  300         int flags;
  301         int onoff;
  302 {
  303         u_int scsi_dlen;
  304         int byte2, page;
  305         struct scsi_select {
  306                 struct scsipi_mode_header header;
  307                 struct scsi_blk_desc blk_desc;
  308                 u_char pdata[MAX(sizeof(struct scsi_tape_dev_conf_page),
  309                     sizeof(struct scsi_tape_dev_compression_page))];
  310         } scsi_pdata;
  311         struct scsi_tape_dev_conf_page *ptr;
  312         struct scsi_tape_dev_compression_page *cptr;
  313         struct scsipi_periph *periph = st->sc_periph;
  314         int error, ison;
  315 
  316         scsi_dlen = sizeof(scsi_pdata);
  317         /*  
  318          * Do DATA COMPRESSION page first.
  319          */
  320         page = SMS_PAGE_CTRL_CURRENT | 0xf;
  321         byte2 = 0;
  322 
  323         /*
  324          * Do the MODE SENSE command...
  325          */
  326 again:
  327         memset(&scsi_pdata, 0, scsi_dlen);
  328         error = scsipi_mode_sense(periph, byte2, page,
  329             &scsi_pdata.header, scsi_dlen, flags | XS_CTL_DATA_ONSTACK,
  330             ST_RETRIES, ST_CTL_TIME);
  331 
  332         if (error) {
  333                 if (byte2 != SMS_DBD) {
  334                         byte2 = SMS_DBD;
  335                         goto again;
  336                 }
  337                 /*
  338                  * Try a different page?
  339                  */
  340                 if (page == (SMS_PAGE_CTRL_CURRENT | 0xf)) {
  341                         page = SMS_PAGE_CTRL_CURRENT | 0x10;
  342                         byte2 = 0;
  343                         goto again;
  344                 }
  345                 return (error);
  346         }
  347 
  348         if (scsi_pdata.header.blk_desc_len)
  349                 ptr = (struct scsi_tape_dev_conf_page *) scsi_pdata.pdata;
  350         else
  351                 ptr = (struct scsi_tape_dev_conf_page *) &scsi_pdata.blk_desc;
  352 
  353         if ((page & SMS_PAGE_CODE) == 0xf) {
  354                 cptr = (struct scsi_tape_dev_compression_page *) ptr;
  355                 ison = (cptr->dce_dcc & DCP_DCE) != 0;
  356                 if (onoff)
  357                         cptr->dce_dcc |= DCP_DCE;
  358                 else
  359                         cptr->dce_dcc &= ~DCP_DCE;
  360                 cptr->pagecode &= ~0x80;
  361         } else {
  362                 ison =  (ptr->sel_comp_alg != 0);
  363                 if (onoff)
  364                         ptr->sel_comp_alg = 1;
  365                 else
  366                         ptr->sel_comp_alg = 0;
  367                 ptr->pagecode &= ~0x80;
  368                 ptr->byte2 = 0;
  369                 ptr->active_partition = 0;
  370                 ptr->wb_full_ratio = 0;
  371                 ptr->rb_empty_ratio = 0;
  372                 ptr->byte8 &= ~0x30;
  373                 ptr->gap_size = 0;
  374                 ptr->byte10 &= ~0xe7;
  375                 ptr->ew_bufsize[0] = 0;
  376                 ptr->ew_bufsize[1] = 0;
  377                 ptr->ew_bufsize[2] = 0;
  378                 ptr->reserved = 0;
  379         }
  380         /*
  381          * There might be a virtue in actually doing the MODE SELECTS,
  382          * but let's not clog the bus over it.
  383          */
  384         if (onoff == ison)
  385                 return (0);
  386 
  387         /*
  388          * Set up for a mode select
  389          */
  390 
  391         scsi_pdata.header.data_length = 0;
  392         scsi_pdata.header.medium_type = 0;
  393         if ((st->flags & ST_DONTBUFFER) == 0)
  394                 scsi_pdata.header.dev_spec = SMH_DSP_BUFF_MODE_ON;
  395         else
  396                 scsi_pdata.header.dev_spec = 0;
  397 
  398         if (scsi_pdata.header.blk_desc_len) {
  399                 scsi_pdata.blk_desc.density = 0;
  400                 scsi_pdata.blk_desc.nblocks[0] = 0;
  401                 scsi_pdata.blk_desc.nblocks[1] = 0;
  402                 scsi_pdata.blk_desc.nblocks[2] = 0;
  403         }
  404 
  405         /*
  406          * Do the command
  407          */
  408         error = scsipi_mode_select(periph, SMS_PF, &scsi_pdata.header,
  409             scsi_dlen, flags | XS_CTL_DATA_ONSTACK, ST_RETRIES, ST_CTL_TIME);
  410 
  411         if (error && (page & SMS_PAGE_CODE) == 0xf) {
  412                 /*
  413                  * Try DEVICE CONFIGURATION page.
  414                  */
  415                 page = SMS_PAGE_CTRL_CURRENT | 0x10;
  416                 goto again;
  417         }
  418         return (error);
  419 }

Cache object: a8b5b14a94495e046c32859ae1bbe656


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