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/i386/isa/wfd.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) 1997,1998  Junichi Satoh <junichi@astec.co.jp>
    3  *   All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions and the following disclaimer as
   10  *    the first lines of this file unmodified.
   11  * 2. Redistributions in binary form must reproduce the above copyright
   12  *    notice, this list of conditions and the following disclaimer in the
   13  *    documentation and/or other materials provided with the distribution.
   14  *
   15  * THIS SOFTWARE IS PROVIDED BY Junichi Satoh ``AS IS'' AND ANY EXPRESS OR
   16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   18  * IN NO EVENT SHALL Junichi Satoh BE LIABLE FOR ANY DIRECT, INDIRECT,
   19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   20  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   24  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   25  *
   26  * $FreeBSD: src/sys/i386/isa/wfd.c,v 1.1.2.7 1999/09/05 08:13:45 peter Exp $
   27  */
   28 
   29 /*
   30  * ATAPI Floppy, LS-120 driver
   31  */
   32 
   33 #include "wdc.h"
   34 #include "wfd.h"
   35 #include "opt_atapi.h"
   36 
   37 #if NWFD > 0 && NWDC > 0 && defined (ATAPI)
   38 
   39 #include <sys/param.h>
   40 #include <sys/systm.h>
   41 #include <sys/kernel.h>
   42 #include <sys/conf.h>
   43 #include <sys/file.h>
   44 #include <sys/ioctl.h>
   45 #include <sys/proc.h>
   46 #include <sys/malloc.h>
   47 #include <sys/buf.h>
   48 #include <sys/disklabel.h>
   49 #include <sys/diskslice.h>
   50 #include <sys/cdio.h>
   51 #include <machine/ioctl_fd.h>
   52 #ifdef DEVFS
   53 #include <sys/devfsext.h>
   54 #endif /*DEVFS*/
   55 
   56 #include <i386/isa/atapi.h>
   57 #include <i386/isa/fdc.h>
   58 
   59 static  d_open_t        wfdbopen;
   60 static  d_close_t       wfdbclose;
   61 static  d_ioctl_t       wfdioctl;
   62 static  d_strategy_t    wfdstrategy;
   63 
   64 #define CDEV_MAJOR 87
   65 #define BDEV_MAJOR 1
   66 static struct cdevsw wfd_cdevsw;
   67 static struct bdevsw wfd_bdevsw = 
   68         { wfdbopen,     wfdbclose,      wfdstrategy,    wfdioctl,
   69           nodump,       nopsize,        0,      "wfd",  &wfd_cdevsw,    -1 };
   70 
   71 #ifndef ATAPI_STATIC
   72 static
   73 #endif
   74 int  wfdattach(struct atapi*, int, struct atapi_params*, int);
   75 
   76 #define NUNIT   (NWDC*2)                /* Max. number of devices */
   77 #define UNIT(d) ((minor(d) >> 3) & 3)   /* Unit part of minor device number */
   78 
   79 #define F_BOPEN         0x0001          /* The block device is opened */
   80 #define F_MEDIA_CHANGED 0x0002          /* The media have changed since open */
   81 #define F_DEBUG         0x0004          /* Print debug info */
   82 
   83 /*
   84  * LS-120 Capabilities and Mechanical Status Page
   85  */
   86 struct cappage {
   87     /* Mode data header */
   88     u_short     data_length;
   89     u_char      medium_type;
   90 #define MDT_UNKNOWN     0x00
   91 #define MDT_NO_DISC     0x70
   92 #define MDT_DOOR_OPEN   0x71
   93 #define MDT_FMT_ERROR   0x72
   94 
   95 #define MDT_2DD_UN      0x10
   96 #define MDT_2DD         0x11
   97 #define MDT_2HD_UN      0x20
   98 #define MDT_2HD_12_98   0x22
   99 #define MDT_2HD_12      0x23
  100 #define MDT_2HD_144     0x24
  101 #define MDT_LS120       0x31
  102 
  103     unsigned        reserved0       :7;
  104     unsigned        wp              :1;     /* Write protect */
  105     u_char          reserved1[4];
  106 
  107     /* Capabilities page */
  108     unsigned        page_code       :6;     /* Page code - Should be 0x5 */
  109 #define CAP_PAGE        0x05
  110     unsigned        reserved1_6     :1;     /* Reserved */
  111     unsigned        ps              :1;     /* The device is capable of saving the page */
  112     u_char          page_length;            /* Page Length - Should be 0x1e */
  113     u_short         transfer_rate;          /* In kilobits per second */
  114     u_char          heads, sectors;         /* Number of heads, Number of sectors per track */
  115     u_short         sector_size;            /* Byes per sector */
  116     u_short         cyls;                   /* Number of cylinders */
  117     u_char          reserved10[10];
  118     u_char          motor_delay;            /* Motor off delay */
  119     u_char          reserved21[7];
  120     u_short         rpm;                    /* Rotations per minute */
  121     u_char          reserved30[2];
  122 };
  123 
  124 /* misuse a flag to identify format operation */
  125 #define B_FORMAT B_XXX
  126 
  127 struct wfd {
  128         struct atapi *ata;              /* Controller structure */
  129         int unit;                       /* IDE bus drive unit */
  130         int lun;                        /* Logical device unit */
  131         int flags;                      /* Device state flags */
  132         int refcnt;                     /* The number of raw opens */
  133         int maxblks;                    /* transfer size limit */
  134         struct buf_queue_head buf_queue;/* Queue of i/o requests */
  135         struct atapi_params *param;     /* Drive parameters table */
  136         struct cappage cap;             /* Capabilities page info */
  137         char description[80];           /* Device description */
  138 #ifdef  DEVFS
  139         void    *cdevs;
  140         void    *bdevs;
  141 #endif
  142         struct diskslices *dk_slices;   /* virtual drives */
  143 };
  144 
  145 struct wfd *wfdtab[NUNIT];      /* Drive info by unit number */
  146 static int wfdnlun = 0;         /* Number of configured drives */
  147 
  148 static void wfd_start (struct wfd *t);
  149 static void wfd_done (struct wfd *t, struct buf *bp, int resid,
  150         struct atapires result);
  151 static void wfd_error (struct wfd *t, struct atapires result);
  152 static int wfd_request_wait (struct wfd *t, u_char cmd, u_char a1, u_char a2,
  153         u_char a3, u_char a4, u_char a5, u_char a6, u_char a7, u_char a8,
  154         u_char a9, char *addr, int count);
  155 static void wfd_describe (struct wfd *t);
  156 static int wfd_eject (struct wfd *t, int closeit);
  157 static void wfdstrategy1(struct buf *bp);
  158 
  159 /*
  160  * Dump the array in hexadecimal format for debugging purposes.
  161  */
  162 static void wfd_dump (int lun, char *label, void *data, int len)
  163 {
  164         u_char *p = data;
  165 
  166         printf ("wfd%d: %s %x", lun, label, *p++);
  167         while (--len > 0)
  168                 printf ("-%x", *p++);
  169         printf ("\n");
  170 }
  171 
  172 #ifndef ATAPI_STATIC
  173 static
  174 #endif
  175 int 
  176 wfdattach (struct atapi *ata, int unit, struct atapi_params *ap, int debug)
  177 {
  178         struct wfd *t;
  179         struct atapires result;
  180         int lun, i;
  181 
  182 #ifdef DEVFS
  183         int     mynor;
  184 #endif
  185         if (wfdnlun >= NUNIT) {
  186                 printf ("wfd: too many units\n");
  187                 return (0);
  188         }
  189         if (!atapi_request_immediate) {
  190                 printf("wfd: configuration error, ATAPI core code not present!\n");
  191                 printf("wfd: check `options ATAPI_STATIC' in your kernel config file!\n");
  192                 return (0);
  193         }
  194         t = malloc (sizeof (struct wfd), M_TEMP, M_NOWAIT);
  195         if (! t) {
  196                 printf ("wfd: out of memory\n");
  197                 return (0);
  198         }
  199         wfdtab[wfdnlun] = t;
  200         bzero(t, sizeof (struct wfd));
  201         bufq_init(&t->buf_queue);
  202         t->ata = ata;
  203         t->unit = unit;
  204         lun = t->lun = wfdnlun++;
  205         t->param = ap;
  206         t->flags = F_MEDIA_CHANGED;
  207         t->refcnt = 0;
  208         if (debug) {
  209                 t->flags |= F_DEBUG;
  210                 /* Print params. */
  211                 wfd_dump (t->lun, "info", ap, sizeof *ap);
  212         }
  213 
  214         /* Get drive capabilities. */
  215         /* Do it twice to avoid the stale media changed state. */
  216         for (i = 0; i < 2; i++) {
  217                 result = atapi_request_immediate (ata, unit, ATAPI_MODE_SENSE,
  218                         0, CAP_PAGE, 0, 0, 0, 0, 
  219                         sizeof (t->cap) >> 8, sizeof (t->cap),
  220                         0, 0, 0, 0, 0, 0, 0, (char*) &t->cap, sizeof (t->cap));
  221         }
  222 
  223         if (result.code == RES_ERR &&
  224             (result.error & AER_SKEY) == AER_SK_UNIT_ATTENTION)
  225                 result = atapi_request_immediate (ata, unit, ATAPI_MODE_SENSE,
  226                         0, CAP_PAGE, 0, 0, 0, 0, sizeof (t->cap) >> 8,
  227                         sizeof (t->cap), 0, 0, 0, 0, 0, 0, 0,
  228                         (char*) &t->cap, sizeof (t->cap));
  229 
  230         /* Some drives have shorter capabilities page. */
  231         if (result.code == RES_UNDERRUN)
  232                 result.code = 0;
  233 
  234         if (result.code == 0) {
  235                 wfd_describe (t);
  236                 if (t->flags & F_DEBUG)
  237                         wfd_dump (t->lun, "cap", &t->cap, sizeof t->cap);
  238         } else
  239                 return -1;
  240 
  241         /*
  242          * The IOMEGA ZIP 100, at firmware 21.* and 23.* at least
  243          * is known to lock up if transfers > 64 blocks are
  244          * requested.
  245          */
  246         if (!strcmp(ap->model, "IOMEGA  ZIP 100       ATAPI")) {
  247                 printf("wfd%d: buggy Zip drive, 64-block transfer limit set\n",
  248                        t->lun);
  249                 t->maxblks = 64;
  250         } else {
  251                 t->maxblks = 0; /* no limit */
  252         }
  253         
  254         
  255 
  256 #ifdef DEVFS
  257         mynor = dkmakeminor(t->lun, WHOLE_DISK_SLICE, RAW_PART);
  258         t->bdevs = devfs_add_devswf(&wfd_bdevsw, mynor, 
  259                                     DV_BLK, UID_ROOT, GID_OPERATOR, 0640,
  260                                     "wfd%d", t->lun);
  261         t->cdevs = devfs_add_devswf(&wfd_cdevsw, mynor, 
  262                                     DV_CHR, UID_ROOT, GID_OPERATOR, 0640,
  263                                     "rwfd%d", t->lun);
  264 #endif /* DEVFS */
  265         return (1);
  266 }
  267 
  268 void wfd_describe (struct wfd *t)
  269 {
  270         int no_print = 0;
  271 
  272         t->cap.cyls = ntohs (t->cap.cyls);
  273         t->cap.sector_size = ntohs (t->cap.sector_size);
  274 
  275         printf ("wfd%d: ", t->lun);
  276         switch (t->cap.medium_type) {
  277         case MDT_UNKNOWN:
  278                 printf ("medium type unknown (no disk)");
  279                 no_print = 1;
  280                 break;
  281         case MDT_2DD_UN:
  282                 printf ("2DD(capacity unknown) floppy disk loaded");
  283                 no_print = 1;
  284                 break;
  285         case MDT_2DD:
  286                 printf ("720KB floppy disk loaded");
  287                 break;
  288         case MDT_2HD_UN:
  289                 printf ("2HD(capacity unknown) floppy disk loaded");
  290                 no_print = 1;
  291                 break;
  292         case MDT_2HD_12_98:
  293                 printf ("1.25MB(PC-9801 format) floppy disk loaded");
  294                 break;
  295         case MDT_2HD_12:
  296                 printf ("1.2MB floppy disk loaded");
  297                 break;
  298         case MDT_2HD_144:
  299                 printf ("1.44MB floppy disk loaded");
  300                 break;
  301         case MDT_LS120:
  302                 printf ("120MB floppy disk loaded");
  303                 break;
  304         case MDT_NO_DISC:
  305                 printf ("no disc inside");
  306                 no_print = 1;
  307                 break;
  308         case MDT_DOOR_OPEN:
  309                 printf ("door open");
  310                 no_print = 1;
  311                 break;
  312         case MDT_FMT_ERROR:
  313                 printf ("medium format error");
  314                 no_print = 1;
  315                 break;
  316         default:
  317                 printf ("medium type=0x%x", t->cap.medium_type);
  318                 break;
  319         }
  320         if (t->cap.wp)
  321                 printf(", write protected");
  322         printf ("\n");
  323 
  324         if (!no_print) {
  325                 printf ("wfd%d: ", t->lun);
  326                 printf ("%lu cyls", t->cap.cyls);
  327                 printf (", %lu heads, %lu S/T", t->cap.heads, t->cap.sectors);
  328                 printf (", %lu B/S", t->cap.sector_size);
  329                 printf ("\n");
  330         }
  331 }
  332 
  333 int wfdbopen (dev_t dev, int flags, int fmt, struct proc *p)
  334 {
  335         int lun = UNIT(dev);
  336         struct wfd *t;
  337         struct atapires result;
  338         int errcode = 0;
  339         struct disklabel label;
  340 
  341         /* Check that the device number is legal
  342          * and the ATAPI driver is loaded. */
  343         if (lun >= wfdnlun || ! atapi_request_immediate)
  344                 return (ENXIO);
  345         t = wfdtab[lun];
  346 
  347         t->flags &= ~F_MEDIA_CHANGED;
  348         /* Lock the media. */
  349         wfd_request_wait (t, ATAPI_PREVENT_ALLOW,
  350                           0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0);
  351 
  352         /* Sense the media type */
  353         result = atapi_request_wait (t->ata, t->unit, ATAPI_MODE_SENSE,
  354                                      0, CAP_PAGE, 0, 0, 0, 0, 
  355                                      sizeof (t->cap) >> 8, sizeof (t->cap),
  356                                      0, 0, 0, 0, 0, 0, 0, 
  357                                      (char*) &t->cap, sizeof (t->cap));
  358         if (result.code)
  359                 printf ("wfd%d: Sense the media type is failed.\n", t->lun);
  360         else {
  361                 t->cap.cyls = ntohs (t->cap.cyls);
  362                 t->cap.sector_size = ntohs (t->cap.sector_size);
  363         }
  364 
  365         /* Build label for whole disk. */
  366         bzero(&label, sizeof label);
  367         label.d_secsize = t->cap.sector_size;
  368         label.d_nsectors = t->cap.sectors;
  369         label.d_ntracks = t->cap.heads;
  370         label.d_ncylinders = t->cap.cyls;
  371         label.d_secpercyl = t->cap.heads * t->cap.sectors;
  372         label.d_rpm = 720;
  373         label.d_secperunit = label.d_secpercyl * t->cap.cyls;
  374 
  375         /* Initialize slice tables. */
  376         errcode = dsopen("wfd", dev, fmt, &t->dk_slices, &label, wfdstrategy1,
  377                          (ds_setgeom_t *)NULL, &wfd_bdevsw, &wfd_cdevsw);
  378         if (errcode != 0)
  379                 return errcode;
  380 
  381         t->flags |= F_BOPEN;
  382         return (0);
  383 }
  384 
  385 /*
  386  * Close the device.  Only called if we are the LAST
  387  * occurence of an open device.
  388  */
  389 int wfdbclose (dev_t dev, int flags, int fmt, struct proc *p)
  390 {
  391         int lun = UNIT(dev);
  392         struct wfd *t = wfdtab[lun];
  393 
  394         dsclose(dev, fmt, t->dk_slices);
  395         if(!dsisopen(t->dk_slices)) {
  396                 /* If we were the last open of the entire device, release it. */
  397                 if (! t->refcnt)
  398                         wfd_request_wait (t, ATAPI_PREVENT_ALLOW,
  399                                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
  400                 t->flags &= ~F_BOPEN;
  401         }
  402         return (0);
  403 }
  404 
  405 static void
  406 wfdstrategy1(struct buf *bp)
  407 {
  408         /*
  409          * XXX - do something to make wdstrategy() but not this block while
  410          * we're doing dsinit() and dsioctl().
  411          */
  412         wfdstrategy(bp);
  413 }
  414 
  415 /*
  416  * Actually translate the requested transfer into one the physical driver can
  417  * understand. The transfer is described by a buf and will include only one
  418  * physical transfer.
  419  */
  420 void wfdstrategy (struct buf *bp)
  421 {
  422         int lun = UNIT(bp->b_dev);
  423         struct wfd *t = wfdtab[lun];
  424         int x;
  425 
  426         /* If it's a null transfer, return immediatly. */
  427         if (bp->b_bcount == 0) {
  428                 bp->b_resid = 0;
  429                 biodone (bp);
  430                 return;
  431         }
  432 
  433         /*
  434          * Do bounds checking, adjust transfer, and set b_pblkno.
  435          */
  436         if (dscheck(bp, t->dk_slices) <= 0) {
  437                 biodone(bp);
  438                 return;
  439         }
  440 
  441         x = splbio();
  442 
  443         /* Place it in the queue of disk activities for this disk. */
  444         bufqdisksort(&t->buf_queue, bp);
  445 
  446         /* Tell the device to get going on the transfer if it's
  447          * not doing anything, otherwise just wait for completion. */
  448         wfd_start (t);
  449         splx(x);
  450 }
  451 
  452 /*
  453  * Look to see if there is a buf waiting for the device
  454  * and that the device is not already busy. If both are true,
  455  * It dequeues the buf and creates an ATAPI command to perform the
  456  * transfer in the buf.
  457  * The bufs are queued by the strategy routine (wfdstrategy).
  458  * Must be called at the correct (splbio) level.
  459  */
  460 static void wfd_start (struct wfd *t)
  461 {
  462         struct buf *bp = bufq_first(&t->buf_queue);
  463         u_long blkno, nblk;
  464         u_char op_code;
  465         long count;
  466         int pxcount, pxnblk;
  467         u_char *pxdest;
  468         
  469 
  470         /* See if there is a buf to do and we are not already doing one. */
  471         if (! bp)
  472                 return;
  473 
  474         /* Unqueue the request. */
  475         bufq_remove(&t->buf_queue, bp);
  476 
  477         /* We have a buf, now we should make a command
  478          * First, translate the block to absolute and put it in terms of the
  479          * logical blocksize of the device. */
  480         blkno = bp->b_pblkno / (t->cap.sector_size / 512);
  481         nblk = (bp->b_bcount + (t->cap.sector_size - 1)) / t->cap.sector_size;
  482 
  483         if ((t->maxblks == 0) || (nblk <= t->maxblks)) {
  484 
  485                 if(bp->b_flags & B_READ) {
  486                         op_code = ATAPI_READ_BIG;
  487                         count = bp->b_bcount;
  488                 } else {
  489                         op_code = ATAPI_WRITE_BIG;
  490                         count = -bp->b_bcount;
  491                 }
  492 
  493                 /* only one transfer */
  494                 (int)bp->b_driver1 = 0;
  495                 (int)bp->b_driver2 = 0;
  496                 atapi_request_callback (t->ata, t->unit, op_code, 0,
  497                                         blkno>>24, blkno>>16, blkno>>8, blkno,
  498                                         0, nblk>>8, nblk, 0, 0,
  499                                         0, 0, 0, 0, 0, 
  500                                         (u_char*)bp->b_un.b_addr, count, 
  501                                         (void*)wfd_done, t, bp);
  502         } else {
  503 
  504                 /*
  505                  * We can't handle this request in a single
  506                  * read/write operation.  Instead, queue a set of
  507                  * transfers, and record the number of transfers
  508                  * and the running residual in the b_driver
  509                  * fields of the bp.
  510                  */ 
  511 
  512                 if(bp->b_flags & B_READ) {
  513                         op_code = ATAPI_READ_BIG;
  514                 } else {
  515                         op_code = ATAPI_WRITE_BIG;
  516                 }
  517 
  518                 /* calculate number of transfers */
  519                 (int)bp->b_driver1 = (nblk - 1) / t->maxblks;
  520                 (int)bp->b_driver2 = 0;
  521 
  522                 pxdest = (u_char *)bp->b_un.b_addr;
  523                 pxcount = bp->b_bcount;
  524 
  525                 /* construct partial transfer requests */
  526                 while (nblk > 0) {
  527                         pxnblk = min(nblk, t->maxblks);
  528                         count = min(pxcount, t->maxblks * t->cap.sector_size);
  529 
  530                         atapi_request_callback(t->ata, t->unit, op_code, 0,
  531                                                blkno>>24, blkno>>16, blkno>>8,
  532                                                blkno, 0, pxnblk>>8, pxnblk, 
  533                                                0, 0, 0, 0, 0, 0, 0,
  534                                                pxdest, 
  535                                                (bp->b_flags & B_READ) ?
  536                                                count : -count, 
  537                                                (void*)wfd_done, t, bp);
  538                         nblk -= pxnblk;
  539                         pxcount -= count;
  540                         pxdest += count;
  541                         blkno += pxnblk;
  542                 }
  543         }
  544 }
  545 
  546 static void wfd_done (struct wfd *t, struct buf *bp, int resid,
  547         struct atapires result)
  548 {
  549                 
  550         if (result.code) {
  551                 wfd_error (t, result);
  552                 bp->b_error = EIO;
  553                 bp->b_flags |= B_ERROR;
  554         } else
  555                 (int)bp->b_driver2 += resid;
  556         /*
  557          * We can't call biodone until all outstanding
  558          * transfer fragments are handled.  If one hits
  559          * an error, we will be returning an error, but
  560          * only when all are complete.
  561          */
  562         if (((int)bp->b_driver1)-- <= 0) {
  563                 bp->b_resid = (int)bp->b_driver2;
  564                 biodone (bp);
  565         }
  566         
  567         wfd_start (t);
  568 }
  569 
  570 static void wfd_error (struct wfd *t, struct atapires result)
  571 {
  572         if (result.code != RES_ERR)
  573                 return;
  574         switch (result.error & AER_SKEY) {
  575         case AER_SK_NOT_READY:
  576                 if (result.error & ~AER_SKEY) {
  577                         /* Not Ready */
  578                         printf ("wfd%d: not ready\n", t->lun);
  579                         return;
  580                 }
  581                 /* Tray open. */
  582                 if (! (t->flags & F_MEDIA_CHANGED))
  583                         printf ("wfd%d: tray open\n", t->lun);
  584                 t->flags |= F_MEDIA_CHANGED;
  585                 return;
  586 
  587         case AER_SK_UNIT_ATTENTION:
  588                 /* Media changed. */
  589                 if (! (t->flags & F_MEDIA_CHANGED))
  590                         printf ("wfd%d: media changed\n", t->lun);
  591                 t->flags |= F_MEDIA_CHANGED;
  592                 return;
  593 
  594         case AER_SK_ILLEGAL_REQUEST:
  595                 /* Unknown command or invalid command arguments. */
  596                 if (t->flags & F_DEBUG)
  597                         printf ("wfd%d: invalid command\n", t->lun);
  598                 return;
  599         }
  600         printf ("wfd%d: i/o error, status=%b, error=%b\n", t->lun,
  601                 result.status, ARS_BITS, result.error, AER_BITS);
  602 }
  603 
  604 static int wfd_request_wait (struct wfd *t, u_char cmd, u_char a1, u_char a2,
  605         u_char a3, u_char a4, u_char a5, u_char a6, u_char a7, u_char a8,
  606         u_char a9, char *addr, int count)
  607 {
  608         struct atapires result;
  609 
  610         result = atapi_request_wait (t->ata, t->unit, cmd,
  611                 a1, a2, a3, a4, a5, a6, a7, a8, a9, 0, 0, 0, 0, 0, 0,
  612                 addr, count);
  613         if (result.code) {
  614                 wfd_error (t, result);
  615                 return (EIO);
  616         }
  617         return (0);
  618 }
  619 
  620 /*
  621  * Perform special action on behalf of the user.
  622  * Knows about the internals of this device
  623  */
  624 int wfdioctl (dev_t dev, int cmd, caddr_t addr, int flag, struct proc *p)
  625 {
  626         int lun = UNIT(dev);
  627         struct wfd *t = wfdtab[lun];
  628         int error = 0;
  629 
  630         struct disklabel *dl;
  631         char buffer[DEV_BSIZE];
  632 
  633         error = dsioctl("wfd", dev, cmd, addr, flag, &t->dk_slices,
  634                         wfdstrategy1, (ds_setgeom_t *)NULL);
  635         if (error != -1)
  636                 return (error);
  637 
  638         if (t->flags & F_MEDIA_CHANGED)
  639                 switch (cmd) {
  640                 case CDIOCSETDEBUG:
  641                 case CDIOCCLRDEBUG:
  642                 case CDIOCRESET:
  643                         /* These ops are media change transparent. */
  644                         break;
  645                 default:
  646                         /* Lock the media. */
  647                         wfd_request_wait (t, ATAPI_PREVENT_ALLOW,
  648                                 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0);
  649                         break;
  650                 }
  651         switch (cmd) {
  652         case CDIOCSETDEBUG:
  653                 if (p->p_cred->pc_ucred->cr_uid)
  654                         return (EPERM);
  655                 t->flags |= F_DEBUG;
  656                 atapi_debug (t->ata, 1);
  657                 return 0;
  658         case CDIOCCLRDEBUG:
  659                 if (p->p_cred->pc_ucred->cr_uid)
  660                         return (EPERM);
  661                 t->flags &= ~F_DEBUG;
  662                 atapi_debug (t->ata, 0);
  663                 return 0;
  664         case CDIOCRESET:
  665                 if (p->p_cred->pc_ucred->cr_uid)
  666                         return (EPERM);
  667                 return wfd_request_wait (t, ATAPI_TEST_UNIT_READY,
  668                         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
  669         case CDIOCEJECT:
  670                 /* Don't allow eject if the device is opened
  671                  * by somebody (not us) in block mode. */
  672                 if ((t->flags & F_BOPEN) && t->refcnt)
  673                         return (EBUSY);
  674                 return wfd_eject (t, 0);
  675         case CDIOCCLOSE:
  676                 if ((t->flags & F_BOPEN) && t->refcnt)
  677                         return (0);
  678                 return wfd_eject (t, 1);
  679         default:
  680                 return (ENOTTY);
  681         }
  682         return (error);
  683 }
  684 
  685 static int wfd_eject (struct wfd *t, int closeit)
  686 {
  687         struct atapires result;
  688 
  689         /* Try to stop the disc. */
  690         result = atapi_request_wait (t->ata, t->unit, ATAPI_START_STOP,
  691                 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
  692 
  693         if (result.code == RES_ERR &&
  694             ((result.error & AER_SKEY) == AER_SK_NOT_READY ||
  695             (result.error & AER_SKEY) == AER_SK_UNIT_ATTENTION)) {
  696                 int err;
  697 
  698                 if (!closeit)
  699                         return (0);
  700                 /*
  701                  * The disc was unloaded.
  702                  * Load it (close tray).
  703                  * Read the table of contents.
  704                  */
  705                 err = wfd_request_wait (t, ATAPI_START_STOP,
  706                         0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0);
  707                 if (err)
  708                         return (err);
  709 
  710                 /* Lock the media. */
  711                 wfd_request_wait (t, ATAPI_PREVENT_ALLOW,
  712                         0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0);
  713 
  714                 return (0);
  715         }
  716 
  717         if (result.code) {
  718                 wfd_error (t, result);
  719                 return (EIO);
  720         }
  721 
  722         if (closeit)
  723                 return (0);
  724 
  725         /* Give it some time to stop spinning. */
  726         tsleep ((caddr_t)&lbolt, PRIBIO, "wfdej1", 0);
  727         tsleep ((caddr_t)&lbolt, PRIBIO, "wfdej2", 0);
  728 
  729         /* Unlock. */
  730         wfd_request_wait (t, ATAPI_PREVENT_ALLOW,
  731                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
  732 
  733         /* Eject. */
  734         t->flags |= F_MEDIA_CHANGED;
  735         return wfd_request_wait (t, ATAPI_START_STOP,
  736                 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0);
  737 }
  738 
  739 #ifdef WFD_MODULE
  740 /*
  741  * Loadable ATAPI Floppy driver stubs.
  742  */
  743 #include <sys/exec.h>
  744 #include <sys/sysent.h>
  745 #include <sys/lkm.h>
  746 
  747 /*
  748  * Construct lkm_dev structures (see lkm.h).
  749  * Our bdevsw/cdevsw slot numbers are 19/69.
  750  */
  751 
  752 
  753 MOD_DEV(wfd, LM_DT_BLOCK, BDEV_MAJOR, &wfd_bdevsw);
  754 MOD_DEV(rwfd, LM_DT_CHAR, CDEV_MAJOR, &wfd_cdevsw);
  755 
  756 /*
  757  * Function called when loading the driver.
  758  */
  759 int wfd_load (struct lkm_table *lkmtp, int cmd)
  760 {
  761         struct atapi *ata;
  762         int n, u;
  763 
  764         if (! atapi_start)
  765                 /* No ATAPI driver available. */
  766                 return EPROTONOSUPPORT;
  767         n = 0;
  768         for (ata=atapi_tab; ata<atapi_tab+2; ++ata)
  769                 if (ata->port)
  770                         for (u=0; u<2; ++u)
  771                                 /* Probing controller ata->ctrlr, unit u. */
  772                                 if (ata->params[u] && ! ata->attached[u] &&
  773                                     wfdattach (ata, u, ata->params[u],
  774                                     ata->debug) >= 0)
  775                                 {
  776                                         /* Drive found. */
  777                                         ata->attached[u] = 1;
  778                                         ++n;
  779                                 }
  780         if (! n)
  781                 /* No IDE Floppies found. */
  782                 return ENXIO;
  783         return 0;
  784 }
  785 
  786 /*
  787  * Function called when unloading the driver.
  788  */
  789 int wfd_unload (struct lkm_table *lkmtp, int cmd)
  790 {
  791         struct wfd **t;
  792 
  793         for (t=wfdtab; t<wfdtab+wfdnlun; ++t)
  794                 if (((*t)->flags & F_BOPEN) || (*t)->refcnt)
  795                         /* The device is opened, cannot unload the driver. */
  796                         return EBUSY;
  797         for (t=wfdtab; t<wfdtab+wfdnlun; ++t) {
  798                 (*t)->ata->attached[(*t)->unit] = 0;
  799                 free (*t, M_TEMP);
  800         }
  801         wfdnlun = 0;
  802         bzero (wfdtab, sizeof(wfdtab));
  803         return 0;
  804 }
  805 
  806 /*
  807  * Dispatcher function for the module (load/unload/stat).
  808  */
  809 int wfd_mod (struct lkm_table *lkmtp, int cmd, int ver)
  810 {
  811         int err = 0;
  812 
  813         if (ver != LKM_VERSION)
  814                 return EINVAL;
  815 
  816         if (cmd == LKM_E_LOAD)
  817                 err = wfd_load (lkmtp, cmd);
  818         else if (cmd == LKM_E_UNLOAD)
  819                 err = wfd_unload (lkmtp, cmd);
  820         if (err)
  821                 return err;
  822 
  823         /* XXX Poking around in the LKM internals like this is bad.
  824          */
  825         /* Register the cdevsw entry. */
  826         lkmtp->private.lkm_dev = & MOD_PRIVATE(rwfd);
  827         err = lkmdispatch (lkmtp, cmd);
  828         if (err)
  829                 return err;
  830 
  831         /* Register the bdevsw entry. */
  832         lkmtp->private.lkm_dev = & MOD_PRIVATE(wfd);
  833         return lkmdispatch (lkmtp, cmd);
  834 }
  835 #endif /* WFD_MODULE */
  836 
  837 static wfd_devsw_installed = 0;
  838 
  839 static void     wfd_drvinit(void *unused)
  840 {
  841         if( ! wfd_devsw_installed ) {
  842                 bdevsw_add_generic(BDEV_MAJOR, CDEV_MAJOR, &wfd_bdevsw);
  843                 wfd_devsw_installed = 1;
  844         }
  845 }
  846 
  847 SYSINIT(wfddev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,wfd_drvinit,NULL)
  848 
  849 
  850 #endif /* NWFD && NWDC && ATAPI */

Cache object: 5b70aef68b5adc05f9760c3f9f31eba6


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