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/od.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) 1995,1996 Shunsuke Akiyama.  All rights reserved.
    3  *
    4  * Redistribution and use in source and binary forms, with or without
    5  * modification, are permitted provided that the following conditions
    6  * are met:
    7  * 1. Redistributions of source code must retain the above copyright
    8  *    notice, this list of conditions and the following disclaimer.
    9  * 2. Redistributions in binary form must reproduce the above copyright
   10  *    notice, this list of conditions and the following disclaimer in the
   11  *    documentation and/or other materials provided with the distribution.
   12  * 3. All advertising materials mentioning features or use of this software
   13  *    must display the following acknowledgement:
   14  *      This product includes software developed by Shunsuke Akiyama.
   15  * 4. Neither the name of the author nor the names of any co-contributors
   16  *    may be used to endorse or promote products derived from this software
   17  *    without specific prior written permission.
   18  *
   19  * THIS SOFTWARE IS PROVIDED BY Shunsuke Akiyama AND CONTRIBUTORS ``AS IS''
   20  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   22  * ARE DISCLAIMED.  IN NO EVENT SHALL Shunsuke Akiyama OR CONTRIBUTORS BE
   23  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   29  * POSSIBILITY OF SUCH DAMAGE.
   30  *
   31  * $FreeBSD: src/sys/scsi/od.c,v 1.22.2.4 1999/09/05 08:21:36 peter Exp $
   32  */
   33 
   34 /*
   35  * Compile option defines:
   36  */
   37 
   38 /*
   39  * If drive returns sense key as 0x02 with vendor specific additional
   40  * sense code (ASC) and additional sense code qualifier (ASCQ), or
   41  * illegal ASC and ASCQ. This cause an error (NOT READY) and retrying.
   42  * To suppress this, uncomment following.
   43  * Or put "options OD_BOGUS_NOT_READY" entry into your kernel
   44  * configuration file.
   45  *
   46 #define OD_BOGUS_NOT_READY
   47  */
   48 
   49 /*
   50  * For an automatic spindown, try this.  Again, preferrably as an
   51  * option in your config file.
   52  * WARNING!  Use at your own risk.  Joerg's ancient SONY SMO drive
   53  * groks it fine, while Shunsuke's Fujitsu chokes on it and times
   54  * out.
   55 #define OD_AUTO_TURNOFF
   56  */
   57 
   58 #include "opt_bounce.h"
   59 #include "opt_scsi.h"
   60 #include "opt_od.h"
   61 
   62 #define SPLOD splbio
   63 #include <sys/types.h>
   64 #include <sys/param.h>
   65 #include <sys/kernel.h>
   66 #include <sys/dkbad.h>
   67 #include <sys/systm.h>
   68 #include <sys/conf.h>
   69 #include <sys/file.h>
   70 #include <sys/stat.h>
   71 #include <sys/ioctl.h>
   72 #include <sys/buf.h>
   73 #include <sys/uio.h>
   74 #include <sys/malloc.h>
   75 #include <sys/cdio.h>
   76 #include <sys/errno.h>
   77 #include <sys/dkstat.h>
   78 #include <sys/disklabel.h>
   79 #include <sys/diskslice.h>
   80 #ifdef DEVFS
   81 #include <sys/devfsext.h>
   82 #endif /*DEVFS*/
   83 #include <scsi/scsi_all.h>
   84 #include <scsi/scsi_disk.h>
   85 #include <scsi/scsiconf.h>
   86 #include <vm/vm.h>
   87 #include <sys/dkstat.h>
   88 #include <machine/md_var.h>
   89 
   90 static u_int32_t odstrats, odqueues;
   91 
   92 #define SECSIZE         512     /* default sector size */
   93 #define ODOUTSTANDING   4
   94 #define OD_RETRIES      4
   95 
   96 #define PARTITION(dev)  dkpart(dev)
   97 #define ODUNIT(dev)     dkunit(dev)
   98 
   99 /* XXX introduce a dkmodunit() macro for this. */
  100 #define ODSETUNIT(DEV, U) \
  101  makedev(major(DEV), dkmakeminor((U), dkslice(DEV), dkpart(DEV)))
  102 
  103 struct scsi_data {
  104         u_int32_t flags;
  105 #define ODINIT          0x04    /* device has been init'd */
  106         struct disk_parms {
  107                 u_char    heads;        /* Number of heads */
  108                 u_int16_t cyls;         /* Number of cylinders (fictitious) */
  109                 u_int16_t sectors;      /* Number of sectors/track */
  110                 u_int16_t secsiz;       /* Number of bytes/sector */
  111                 u_int32_t disksize;     /* total number sectors */
  112                 u_int16_t rpm;          /* medium rotation rate */
  113         } params;
  114         struct diskslices *dk_slices;   /* virtual drives */
  115         struct buf_queue_head buf_queue;
  116         int dkunit;             /* disk stats unit number */
  117 #ifdef DEVFS
  118         /* Eventually move all these to common disk struct. */
  119         void    *b_devfs_token;
  120         void    *c_devfs_token;
  121         void    *ctl_devfs_token;
  122 #endif
  123 };
  124 
  125 static errval   od_get_parms __P((int unit, int flags));
  126 #ifdef notyet
  127 static errval   od_reassign_blocks __P((int unit, int block));
  128 #endif
  129 static u_int32_t        od_size __P((int unit, int flags));
  130 static int      od_sense_handler __P((struct scsi_xfer *));
  131 static void     odstart __P((u_int32_t, u_int32_t));
  132 static void     odstrategy1 __P((struct buf *));
  133 
  134 static dev_t odsetunit(dev_t dev, int unit) { return ODSETUNIT(dev, unit); }
  135 static int odunit(dev_t dev) { return ODUNIT(dev); }
  136 
  137 static errval od_open __P((dev_t dev, int mode, int fmt, struct proc *p,
  138                            struct scsi_link *sc_link));
  139 static errval od_ioctl(dev_t dev, int cmd, caddr_t addr, int flag,
  140                        struct proc *p, struct scsi_link *sc_link);
  141 static errval od_close __P((dev_t dev, int fflag, int fmt, struct proc *p,
  142                             struct scsi_link *sc_link));
  143 static void od_strategy(struct buf *bp, struct scsi_link *sc_link);
  144 
  145 static  d_open_t        odopen;
  146 static  d_close_t       odclose;
  147 static  d_ioctl_t       odioctl;
  148 static  d_strategy_t    odstrategy;
  149 
  150 #define CDEV_MAJOR 70
  151 #define BDEV_MAJOR 20
  152 static struct cdevsw od_cdevsw;
  153 static struct bdevsw od_bdevsw = 
  154         { odopen,       odclose,        odstrategy,     odioctl,        /*20*/
  155           nodump,       nopsize,        0,      "od",   &od_cdevsw,     -1 };
  156 
  157 
  158 /*
  159  * Actually include the interface routines
  160  */
  161 SCSI_DEVICE_ENTRIES(od)
  162 
  163 static struct scsi_device od_switch =
  164 {
  165         od_sense_handler,
  166         odstart,                /* have a queue, served by this */
  167         NULL,                   /* have no async handler */
  168         NULL,                   /* Use default 'done' routine */
  169         "od",
  170         0,
  171         {0, 0},
  172         0,                      /* Link flags */
  173         odattach,
  174         "Optical",
  175         odopen,
  176         sizeof(struct scsi_data),
  177         T_OPTICAL,
  178         odunit,
  179         odsetunit,
  180         od_open,
  181         od_ioctl,
  182         od_close,
  183         od_strategy,
  184 };
  185 
  186 static inline void
  187 od_registerdev(int unit)
  188 {
  189         if(dk_ndrive < DK_NDRIVE) {
  190                 sprintf(dk_names[dk_ndrive], "od%d", unit);
  191                 dk_wpms[dk_ndrive] = (4*1024*1024/2);   /* 4MB/sec */
  192                 SCSI_DATA(&od_switch, unit)->dkunit = dk_ndrive++;
  193         } else {
  194                 SCSI_DATA(&od_switch, unit)->dkunit = -1;
  195         }
  196 }
  197 
  198 
  199 /*
  200  * The routine called by the low level scsi routine when it discovers
  201  * a device suitable for this driver.
  202  */
  203 static errval
  204 odattach(struct scsi_link *sc_link)
  205 {
  206         u_int32_t unit;
  207         struct disk_parms *dp;
  208 #ifdef DEVFS
  209         int     mynor;
  210 #endif
  211 
  212         struct scsi_data *od = sc_link->sd;
  213 
  214         unit = sc_link->dev_unit;
  215 
  216         dp = &(od->params);
  217 
  218         if (sc_link->opennings > ODOUTSTANDING)
  219                 sc_link->opennings = ODOUTSTANDING;
  220 
  221         bufq_init(&od->buf_queue);
  222         /*
  223          * Use the subdriver to request information regarding
  224          * the drive. We cannot use interrupts yet, so the
  225          * request must specify this.
  226          */
  227         scsi_start_unit(sc_link, SCSI_NOSLEEP | SCSI_NOMASK
  228                                  | SCSI_ERR_OK | SCSI_SILENT);
  229         od_get_parms(unit, SCSI_NOSLEEP | SCSI_NOMASK | SCSI_SILENT);
  230         /*
  231          * if we don't have actual parameters, assume 512 bytes/sec
  232          * (could happen on removable media - MOD)
  233          * -- this avoids the division below from falling over
  234          */
  235         if(dp->secsiz == 0) dp->secsiz = SECSIZE;
  236         if (dp->disksize != 0) {
  237                 printf("%ldMB (%ld %d byte sectors)",
  238                     dp->disksize / ((1024L * 1024L) / dp->secsiz),
  239                     dp->disksize,
  240                     dp->secsiz);
  241         } else {
  242                 printf("od not present");
  243         }
  244 
  245 #ifndef SCSI_REPORT_GEOMETRY
  246         if ( (sc_link->flags & SDEV_BOOTVERBOSE) )
  247 #endif
  248         {
  249                 sc_print_addr(sc_link);
  250                 printf("with approximate %d cyls, %d heads, and %d sectors/track",
  251                 dp->cyls, dp->heads, dp->sectors);
  252         }
  253 #ifdef OD_AUTO_TURNOFF
  254         scsi_stop_unit(sc_link, 0, SCSI_ERR_OK | SCSI_SILENT);
  255 #endif /* OD_AUTO_TURNOFF */
  256 
  257         od->flags |= ODINIT;
  258         od_registerdev(unit);
  259 
  260 #ifdef DEVFS
  261         mynor = dkmakeminor(unit, WHOLE_DISK_SLICE, RAW_PART);
  262         od->b_devfs_token = devfs_add_devswf(&od_bdevsw, mynor, DV_BLK,
  263                                              UID_ROOT, GID_OPERATOR, 0640,
  264                                              "od%d", unit);
  265         od->c_devfs_token = devfs_add_devswf(&od_cdevsw, mynor, DV_CHR,
  266                                              UID_ROOT, GID_OPERATOR, 0640,
  267                                              "rod%d", unit);
  268         mynor = dkmakeminor(unit, 0, 0);        /* XXX */
  269         od->ctl_devfs_token = devfs_add_devswf(&od_cdevsw,
  270                                                mynor | SCSI_CONTROL_MASK,
  271                                                DV_CHR,
  272                                                UID_ROOT, GID_WHEEL, 0600,
  273                                                "rod%d.ctl", unit);
  274 #endif
  275 
  276         return 0;
  277 }
  278 
  279 /*
  280  * open the device. Make sure the partition info is a up-to-date as can be.
  281  */
  282 static errval
  283 od_open(dev, mode, fmt, p, sc_link)
  284         dev_t   dev;
  285         int     mode;
  286         int     fmt;
  287         struct proc *p;
  288         struct scsi_link *sc_link;
  289 {
  290         errval  errcode = 0;
  291         u_int32_t unit;
  292         struct disklabel label;
  293         struct scsi_data *od;
  294 
  295         unit = ODUNIT(dev);
  296         od = sc_link->sd;
  297 
  298         /*
  299          * Make sure the disk has been initialized
  300          * At some point in the future, get the scsi driver
  301          * to look for a new device if we are not initted
  302          */
  303         if ((!od) || (!(od->flags & ODINIT))) {
  304                 return ENXIO;
  305         }
  306 
  307         SC_DEBUG(sc_link, SDEV_DB1,
  308             ("od_open: dev=0x%lx (unit %ld, partition %d)\n",
  309                 dev, unit, PARTITION(dev)));
  310 
  311         /*
  312          * Try to start the drive, and try to clear "Unit Attention"
  313          * condition, when media had been changed before.
  314          * This operation also clears the SDEV_MEDIA_LOADED flag in its
  315          * error handling routine.
  316          */
  317         scsi_start_unit(sc_link, SCSI_SILENT);
  318         scsi_prevent(sc_link, PR_PREVENT, SCSI_ERR_OK | SCSI_SILENT);
  319 
  320         /*
  321          * Make sure the drive is ready.
  322          */
  323         scsi_test_unit_ready(sc_link, 0);
  324 
  325         SC_DEBUG(sc_link, SDEV_DB3, ("'start' attempted "));
  326 
  327         sc_link->flags |= SDEV_OPEN;    /* unit attn becomes an err now */
  328         /*
  329          * If it's been invalidated, then forget the label.
  330          */
  331         if (!(sc_link->flags & SDEV_MEDIA_LOADED)) {
  332                 /*
  333                  * If somebody still has it open, then forbid re-entry.
  334                  */
  335                 if (dsisopen(od->dk_slices)) {
  336                         errcode = ENXIO;
  337                         goto bad;
  338                 }
  339 
  340                 if (od->dk_slices != NULL)
  341                         dsgone(&od->dk_slices);
  342         }
  343 
  344         /*
  345          * This time actually take notice of error returns
  346          */
  347         if (scsi_test_unit_ready(sc_link, SCSI_SILENT) != 0) {
  348                 SC_DEBUG(sc_link, SDEV_DB3, ("not ready\n"));
  349                 errcode = ENXIO;
  350                 goto bad;
  351         }
  352         SC_DEBUG(sc_link, SDEV_DB3, ("device present\n"));
  353 
  354         /*
  355          * Load the physical device parameters
  356          */
  357         errcode = od_get_parms(unit, 0);        /* sets SDEV_MEDIA_LOADED */
  358         if (errcode) {
  359                 goto bad;
  360         }
  361         switch (od->params.secsiz) {
  362         case SECSIZE :
  363         case 1024 :
  364         case 2048 :
  365                 break;
  366         default :
  367                 printf("od%ld: Can't deal with %d bytes logical blocks\n",
  368                     unit, od->params.secsiz);
  369                 Debugger("od");
  370                 errcode = ENXIO;
  371                 goto bad;
  372         }
  373         SC_DEBUG(sc_link, SDEV_DB3, ("params loaded "));
  374 
  375         /* Build label for whole disk. */
  376         bzero(&label, sizeof label);
  377         label.d_secsize = od->params.secsiz;
  378         label.d_nsectors = od->params.sectors;
  379         label.d_ntracks = od->params.heads;
  380         label.d_ncylinders = od->params.cyls;
  381         label.d_secpercyl = od->params.heads * od->params.sectors;
  382         label.d_rpm = od->params.rpm;   /* maybe wrong */
  383         if (label.d_secpercyl == 0)
  384                 label.d_secpercyl = 64*32;
  385                 /* XXX as long as it's not 0
  386                  *  - readdisklabel divides by it (?)
  387                  */
  388         label.d_secperunit = od->params.disksize;
  389 
  390         /* Initialize slice tables. */
  391         errcode = dsopen("od", dev, fmt, &od->dk_slices, &label, odstrategy1,
  392                          (ds_setgeom_t *)NULL, &od_bdevsw, &od_cdevsw);
  393         if (errcode != 0)
  394                 goto bad;
  395         SC_DEBUG(sc_link, SDEV_DB3, ("Slice tables initialized "));
  396 
  397         SC_DEBUG(sc_link, SDEV_DB3, ("open %ld %ld\n", odstrats, odqueues));
  398 
  399         return 0;
  400 
  401 bad:
  402         if (!dsisopen(od->dk_slices)) {
  403                 scsi_prevent(sc_link, PR_ALLOW, SCSI_ERR_OK | SCSI_SILENT);
  404 #ifdef OD_AUTO_TURNOFF
  405                 scsi_stop_unit(sc_link, 0, SCSI_ERR_OK | SCSI_SILENT);
  406 #endif /* OD_AUTO_TURNOFF */
  407                 sc_link->flags &= ~SDEV_OPEN;
  408         }
  409         return errcode;
  410 }
  411 
  412 /*
  413  * close the device.. only called if we are the LAST occurence of an open
  414  * device.  Convenient now but usually a pain.
  415  */
  416 static errval
  417 od_close(dev, fflag, fmt, p, sc_link)
  418         dev_t   dev;
  419         int     fflag;
  420         int     fmt;
  421         struct proc *p;
  422         struct scsi_link *sc_link;
  423 {
  424         struct scsi_data *od;
  425 
  426         od = sc_link->sd;
  427         dsclose(dev, fmt, od->dk_slices);
  428         if (!dsisopen(od->dk_slices)) {
  429                 scsi_prevent(sc_link, PR_ALLOW, SCSI_SILENT | SCSI_ERR_OK);
  430 #ifdef OD_AUTO_TURNOFF
  431                 scsi_stop_unit(sc_link, 0, SCSI_ERR_OK | SCSI_SILENT);
  432 #endif /* OD_AUTO_TURNOFF */
  433                 sc_link->flags &= ~SDEV_OPEN;
  434         }
  435         return 0;
  436 }
  437 
  438 /*
  439  * Actually translate the requested transfer into one the physical driver
  440  * can understand.  The transfer is described by a buf and will include
  441  * only one physical transfer.
  442  */
  443 static void
  444 od_strategy(struct buf *bp, struct scsi_link *sc_link)
  445 {
  446         u_int32_t opri;
  447         struct scsi_data *od;
  448         u_int32_t unit;
  449 
  450         odstrats++;
  451         unit = ODUNIT((bp->b_dev));
  452         od = sc_link->sd;
  453 
  454         /*
  455          * If the device has been made invalid, error out
  456          */
  457         if (!(sc_link->flags & SDEV_MEDIA_LOADED)) {
  458                 bp->b_error = EIO;
  459                 goto bad;
  460         }
  461 
  462         /*
  463          * Odd number of bytes or negative offset
  464          */
  465         if (bp->b_blkno < 0 || bp->b_bcount % DEV_BSIZE != 0) {
  466                 bp->b_error = EINVAL;
  467                 goto bad;
  468         }
  469         /*
  470          * Do bounds checking, adjust transfer, set b_cylin and b_pbklno.
  471          */
  472         if (dscheck(bp, od->dk_slices) <= 0)
  473                 goto done;      /* XXX check b_resid */
  474 
  475         opri = SPLOD();
  476 
  477         /*
  478          * Use a bounce buffer if necessary
  479          */
  480 #ifdef BOUNCE_BUFFERS
  481         if (sc_link->flags & SDEV_BOUNCE)
  482                 vm_bounce_alloc(bp);
  483 #endif
  484 
  485         /*
  486          * Place it in the queue of disk activities for this disk
  487          */
  488         bufq_insert_tail(&od->buf_queue, bp);
  489 
  490         /*
  491          * Tell the device to get going on the transfer if it's
  492          * not doing anything, otherwise just wait for completion
  493          */
  494         odstart(unit, 0);
  495 
  496         splx(opri);
  497         return /**/;
  498 bad:
  499         bp->b_flags |= B_ERROR;
  500 done:
  501 
  502         /*
  503          * Correctly set the buf to indicate a completed xfer
  504          */
  505         bp->b_resid = bp->b_bcount;
  506         biodone(bp);
  507         return /**/;
  508 }
  509 
  510 static void
  511 odstrategy1(struct buf *bp)
  512 {
  513         /*
  514          * XXX - do something to make odstrategy() but not this block while
  515          * we're doing dsinit() and dsioctl().
  516          */
  517         odstrategy(bp);
  518 }
  519 
  520 /*
  521  * odstart looks to see if there is a buf waiting for the device
  522  * and that the device is not already busy. If both are true,
  523  * It dequeues the buf and creates a scsi command to perform the
  524  * transfer in the buf. The transfer request will call scsi_done
  525  * on completion, which will in turn call this routine again
  526  * so that the next queued transfer is performed.
  527  * The bufs are queued by the strategy routine (odstrategy)
  528  *
  529  * This routine is also called after other non-queued requests
  530  * have been made of the scsi driver, to ensure that the queue
  531  * continues to be drained.
  532  *
  533  * must be called at the correct (highish) spl level
  534  * odstart() is called at SPLOD  from odstrategy and scsi_done
  535  */
  536 static void
  537 odstart(u_int32_t unit, u_int32_t flags)
  538 {
  539         register struct scsi_link *sc_link = SCSI_LINK(&od_switch, unit);
  540         register struct scsi_data *od = sc_link->sd;
  541         struct buf *bp = 0;
  542         struct scsi_rw_big cmd;
  543         u_int32_t blkno, nblk;
  544         u_int32_t secsize;
  545 
  546         SC_DEBUG(sc_link, SDEV_DB2, ("odstart "));
  547         /*
  548          * Check if the device has room for another command
  549          */
  550         while (sc_link->opennings) {
  551 
  552                 /*
  553                  * there is excess capacity, but a special waits
  554                  * It'll need the adapter as soon as we clear out of the
  555                  * way and let it run (user level wait).
  556                  */
  557                 if (sc_link->flags & SDEV_WAITING) {
  558                         return;
  559                 }
  560                 /*
  561                  * See if there is a buf with work for us to do..
  562                  */
  563                 bp = bufq_first(&od->buf_queue);
  564                 if (bp == NULL) {       /* yes, an assign */
  565                         return;
  566                 }
  567                 bufq_remove(&od->buf_queue, bp);
  568 
  569                 /*
  570                  *  If the device has become invalid, abort all the
  571                  * reads and writes until all files have been closed and
  572                  * re-openned
  573                  */
  574                 if (!(sc_link->flags & SDEV_MEDIA_LOADED)) {
  575                         goto bad;
  576                 }
  577                 /*
  578                  * We have a buf, now we know we are going to go through
  579                  * With this thing..
  580                  */
  581                 secsize = od->params.secsiz;
  582                 blkno = bp->b_pblkno / (secsize / DEV_BSIZE);
  583                 if (bp->b_bcount & (secsize - 1))
  584                 {
  585                     goto bad;
  586                 }
  587                 nblk = (bp->b_bcount + (secsize - 1)) / secsize;
  588 
  589                 /*
  590                  *  Fill out the scsi command
  591                  */
  592                 cmd.op_code = (bp->b_flags & B_READ)
  593                     ? READ_BIG : WRITE_BIG;
  594                 scsi_uto4b(blkno, &cmd.addr_3);
  595                 scsi_uto2b(nblk, &cmd.length2);
  596                 cmd.byte2 = cmd.reserved = cmd.control = 0;
  597                 /*
  598                  * Call the routine that chats with the adapter.
  599                  * Note: we cannot sleep as we may be an interrupt
  600                  */
  601                 if (scsi_scsi_cmd(sc_link,
  602                         (struct scsi_generic *) &cmd,
  603                         sizeof(cmd),
  604                         (u_char *) bp->b_un.b_addr,
  605                         bp->b_bcount,
  606                         OD_RETRIES,
  607                         100000,
  608                         bp,
  609                         flags | ((bp->b_flags & B_READ) ?
  610                             SCSI_DATA_IN : SCSI_DATA_OUT))
  611                     == SUCCESSFULLY_QUEUED) {
  612                         odqueues++;
  613                         if(od->dkunit >= 0) {
  614                                 dk_xfer[od->dkunit]++;
  615                                 dk_seek[od->dkunit]++; /* don't know */
  616                                 dk_wds[od->dkunit] += bp->b_bcount >> 6;
  617                         }
  618                 } else {
  619 bad:
  620                         printf("od%ld: oops not queued\n", unit);
  621                         bp->b_error = EIO;
  622                         bp->b_flags |= B_ERROR;
  623                         biodone(bp);
  624                 }
  625         }
  626 }
  627 
  628 /*
  629  * Perform special action on behalf of the user
  630  * Knows about the internals of this device
  631  */
  632 static errval
  633 od_ioctl(dev_t dev, int cmd, caddr_t addr, int flag, struct proc *p,
  634          struct scsi_link *sc_link)
  635 {
  636         /* struct od_cmd_buf *args; */
  637         errval  error;
  638         struct scsi_data *od;
  639 
  640         /*
  641          * Find the device that the user is talking about
  642          */
  643         od = sc_link->sd;
  644         SC_DEBUG(sc_link, SDEV_DB1, ("odioctl (0x%x)", cmd));
  645 
  646         /*
  647          * If the device is not valid.. abandon ship
  648          */
  649         if (!(sc_link->flags & SDEV_MEDIA_LOADED))
  650                 return EIO;
  651 
  652         switch (cmd) {
  653         case DIOCSBAD:
  654                 error = EINVAL;
  655                 break;
  656         case CDIOCEJECT:
  657                 error = scsi_stop_unit(sc_link, 1, 0);
  658                 sc_link->flags &= ~SDEV_MEDIA_LOADED;
  659                 break;
  660         case CDIOCALLOW:
  661                 error = scsi_prevent(sc_link, PR_ALLOW, 0);
  662                 break;
  663         case CDIOCPREVENT:
  664                 error = scsi_prevent(sc_link, PR_PREVENT, 0);
  665                 break;
  666         default:
  667                 error = dsioctl("od", dev, cmd, addr, flag, &od->dk_slices,
  668                                 odstrategy1, (ds_setgeom_t *)NULL);
  669                 if (error == -1) {
  670                         if (PARTITION(dev) != RAW_PART) {
  671                                 error = ENOTTY;
  672                         } else {
  673                                 error = scsi_do_ioctl(dev, cmd, addr,
  674                                                       flag, p, sc_link);
  675                         }
  676                 }
  677                 break;
  678         }
  679         return error;
  680 }
  681 
  682 /*
  683  * Find out from the device what it's capacity is
  684  */
  685 static u_int32_t
  686 od_size(unit, flags)
  687         int     unit, flags;
  688 {
  689         struct scsi_read_cap_data rdcap;
  690         struct scsi_read_capacity rdcap_cmd;
  691         struct scsi_link *sc_link = SCSI_LINK(&od_switch, unit);
  692         struct scsi_data *od = sc_link->sd;
  693         struct scsi_mode_sense mdsense_cmd;
  694         struct scsi_mode_sense_data {
  695                 struct scsi_mode_header header;
  696                 struct blk_desc blk_desc;
  697                 union disk_pages pages;
  698         } scsi_sense;
  699 
  700         /*
  701          * make up a scsi command and ask the scsi driver to do
  702          * it for you.
  703          */
  704         bzero(&rdcap_cmd, sizeof(rdcap_cmd));
  705         rdcap_cmd.op_code = READ_CAPACITY;
  706 
  707         /*
  708          * If the command works, interpret the result as a 4 byte
  709          * number of blocks
  710          */
  711         if (scsi_scsi_cmd(sc_link,
  712                 (struct scsi_generic *) &rdcap_cmd,
  713                 sizeof(rdcap_cmd),
  714                 (u_char *) & rdcap,
  715                 sizeof(rdcap),
  716                 OD_RETRIES,
  717                 10000,
  718                 NULL,
  719                 flags | SCSI_DATA_IN) != 0) {
  720                 return 0;
  721         } else {
  722                 od->params.disksize = scsi_4btou(&rdcap.addr_3) + 1;
  723                 od->params.secsiz = scsi_4btou(&rdcap.length_3);
  724         }
  725 
  726         /*
  727          * do a "mode sense page 4" (rigid disk drive geometry)
  728          */
  729         bzero(&mdsense_cmd, sizeof(mdsense_cmd));
  730         mdsense_cmd.op_code = MODE_SENSE;
  731         mdsense_cmd.page = 4;
  732         mdsense_cmd.length = 0x20;
  733         /*
  734          * If the command worked, use the results to fill out
  735          * the parameter structure
  736          */
  737         if (scsi_scsi_cmd(sc_link,
  738                 (struct scsi_generic *) &mdsense_cmd,
  739                 sizeof(mdsense_cmd),
  740                 (u_char *) & scsi_sense,
  741                 sizeof(scsi_sense),
  742                 OD_RETRIES,
  743                 10000,
  744                 NULL,
  745                 flags | SCSI_SILENT | SCSI_DATA_IN) != 0) {
  746 
  747                 /* default to a fictitious geometry */
  748                 od->params.heads = 64;
  749         } else {
  750                 SC_DEBUG(sc_link, SDEV_DB3,
  751                          ("%ld cyls, %d heads, %d rpm\n",
  752                         scsi_3btou(&scsi_sense.pages.rigid_geometry.ncyl_2),
  753                         scsi_sense.pages.rigid_geometry.nheads,
  754                         scsi_2btou(&scsi_sense.pages.rigid_geometry.medium_rot_rate_1)));
  755 
  756                 od->params.heads = scsi_sense.pages.rigid_geometry.nheads;
  757                 if (od->params.heads == 0)
  758                         od->params.heads = 64; /* fictitious */
  759                 od->params.rpm =
  760                         scsi_2btou(&scsi_sense.pages.rigid_geometry.medium_rot_rate_1);
  761         }
  762 
  763         /*
  764          * do a "mode sense page 3" (format device)
  765          */
  766         bzero(&mdsense_cmd, sizeof(mdsense_cmd));
  767         mdsense_cmd.op_code = MODE_SENSE;
  768         mdsense_cmd.page = 3;
  769         mdsense_cmd.length = 0x20;
  770         /*
  771          * If the command worked, use the results to fill out
  772          * the parameter structure
  773          */
  774         if (scsi_scsi_cmd(sc_link,
  775                 (struct scsi_generic *) &mdsense_cmd,
  776                 sizeof(mdsense_cmd),
  777                 (u_char *) & scsi_sense,
  778                 sizeof(scsi_sense),
  779                 OD_RETRIES,
  780                 10000,
  781                 NULL,
  782                 flags | SCSI_SILENT | SCSI_DATA_IN) != 0) {
  783 
  784                 /* default to a fictitious geometry */
  785                 od->params.sectors = 32;
  786         } else {
  787                 SC_DEBUG(sc_link, SDEV_DB3,
  788                          ("%d secs\n",
  789                         scsi_2btou(&scsi_sense.pages.disk_format.ph_sec_t_1)));
  790 
  791                 od->params.sectors =
  792                         scsi_2btou(&scsi_sense.pages.disk_format.ph_sec_t_1);
  793                 if (od->params.sectors == 0)
  794                         od->params.sectors = 32; /* fictitious */
  795         }
  796 
  797         return od->params.disksize;
  798 }
  799 
  800 #ifdef notyet
  801 /*
  802  * Tell the device to map out a defective block
  803  */
  804 static errval
  805 od_reassign_blocks(unit, block)
  806         int     unit, block;
  807 {
  808         struct scsi_reassign_blocks scsi_cmd;
  809         struct scsi_reassign_blocks_data rbdata;
  810         struct scsi_link *sc_link = SCSI_LINK(&od_switch, unit);
  811 
  812         bzero(&scsi_cmd, sizeof(scsi_cmd));
  813         bzero(&rbdata, sizeof(rbdata));
  814         scsi_cmd.op_code = REASSIGN_BLOCKS;
  815 
  816         rbdata.length_msb = 0;
  817         rbdata.length_lsb = sizeof(rbdata.defect_descriptor[0]);
  818         scsi_uto4b(block, &rbdata.defect_descriptor[0].dlbaddr_3);
  819 
  820         return scsi_scsi_cmd(sc_link,
  821                 (struct scsi_generic *) &scsi_cmd,
  822                 sizeof(scsi_cmd),
  823                 (u_char *) & rbdata,
  824                 sizeof(rbdata),
  825                 OD_RETRIES,
  826                 20000,
  827                 NULL,
  828                 SCSI_DATA_OUT);
  829 }
  830 #endif
  831 
  832 /*
  833  * Get the scsi driver to send a full inquiry to the
  834  * device and use the results to fill out the disk
  835  * parameter structure.
  836  */
  837 static errval
  838 od_get_parms(unit, flags)
  839         int     unit, flags;
  840 {
  841         struct scsi_link *sc_link = SCSI_LINK(&od_switch, unit);
  842         struct scsi_data *od = sc_link->sd;
  843         struct disk_parms *disk_parms = &od->params;
  844         u_int32_t sectors;
  845         errval retval;
  846 
  847         /*
  848          * First check if we have it all loaded
  849          */
  850         if (sc_link->flags & SDEV_MEDIA_LOADED)
  851                 return 0;
  852 
  853         /*
  854          * Use fictitious geometry, this depends on the size of medium.
  855          */
  856         sectors = od_size(unit, flags);
  857         /* od_size() sets secsiz, disksize, sectors, and heads */
  858 
  859         /* fictitious number of cylinders, so that C*H*S <= total */
  860         if (disk_parms->sectors != 0 && disk_parms->heads != 0) {
  861                 disk_parms->cyls =
  862                   sectors / (disk_parms->sectors * disk_parms->heads);
  863         } else {
  864                 disk_parms->cyls = 0;
  865         }
  866 
  867         if (sectors != 0) {
  868                 sc_link->flags |= SDEV_MEDIA_LOADED;
  869                 retval = 0;
  870         } else {
  871                 retval = ENXIO;
  872         }
  873         return retval;
  874 }
  875 
  876 /*
  877  * sense handler: Called to determine what to do when the
  878  * device returns a CHECK CONDITION.
  879  */
  880 
  881 static int
  882 od_sense_handler(struct scsi_xfer *xs)
  883 {
  884         struct scsi_sense_data *sense;
  885         struct scsi_sense_extended *ext;
  886         int asc, ascq;
  887 
  888         sense = &(xs->sense);
  889         ext = (struct scsi_sense_extended *)&(sense->ext.extended);
  890 
  891         /* I don't know what the heck to do with a deferred error,
  892          * so I'll just kick it back to the caller.
  893          */
  894         if ((sense->error_code & SSD_ERRCODE) == 0x71)
  895                 return SCSIRET_CONTINUE;
  896 
  897 #ifdef OD_BOGUS_NOT_READY
  898         if (((sense->error_code & SSD_ERRCODE) == 0x70) &&
  899                 ((sense->ext.extended.flags & SSD_KEY) == 0x02))
  900                 /* No point in retrying Not Ready */
  901                         return SCSIRET_CONTINUE;
  902 #endif
  903 
  904         if (((sense->error_code & SSD_ERRCODE) == 0x70) &&
  905                 ((sense->ext.extended.flags & SSD_KEY) == 0x04))
  906                 /* No point in retrying Hardware Failure */
  907                         return SCSIRET_CONTINUE;
  908 
  909         if (((sense->error_code & SSD_ERRCODE) == 0x70) &&
  910                 ((sense->ext.extended.flags & SSD_KEY) == 0x05))
  911                 /* No point in retrying Illegal Requests */
  912                         return SCSIRET_CONTINUE;
  913 
  914         asc = (ext->extra_len >= 5) ? ext->add_sense_code : 0;
  915         ascq = (ext->extra_len >= 6) ? ext->add_sense_code_qual : 0;
  916 
  917         if (asc == 0x11 || asc == 0x30 || asc == 0x31 || asc == 0x53
  918             || asc == 0x5a) {
  919                 /* Unrecovered errors */
  920                 return SCSIRET_CONTINUE;
  921         }
  922         if (asc == 0x21 && ascq == 0) {
  923                 /* Logical block address out of range */
  924                 return SCSIRET_CONTINUE;
  925         }
  926         if (asc == 0x27 && ascq == 0) {
  927                 /* Write protected */
  928                 return SCSIRET_CONTINUE;
  929         }
  930         if (asc == 0x28 && ascq == 0) {
  931                 /* Not ready to ready transition */
  932                 /* (medium may have changed) */
  933                 return SCSIRET_CONTINUE;
  934         }
  935         if (asc == 0x3a && ascq == 0) {
  936                 /* Medium not present */
  937                 return SCSIRET_CONTINUE;
  938         }
  939 
  940         /* Retry all disk errors.
  941          */
  942         scsi_sense_print(xs);
  943         if (xs->retries)
  944                 printf(", retries:%d\n", xs->retries);
  945         else
  946                 printf(", FAILURE\n");
  947 
  948         return SCSIRET_DO_RETRY;
  949 }
  950 
  951 static od_devsw_installed = 0;
  952 
  953 static void     od_drvinit(void *unused)
  954 {
  955 
  956         if( ! od_devsw_installed ) {
  957                 bdevsw_add_generic(BDEV_MAJOR, CDEV_MAJOR, &od_bdevsw);
  958                 od_devsw_installed = 1;
  959         }
  960 }
  961 
  962 SYSINIT(oddev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,od_drvinit,NULL)

Cache object: ac70c26e409f9272c25fd093909c3ef1


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