Remove the priority part of the priority|flags argument to tsleep(). Only
[dragonfly.git] / sys / dev / disk / wfd / wfd.c
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.35 2000/01/29 16:00:33 peter Exp $
27  * $DragonFly: src/sys/dev/disk/wfd/Attic/wfd.c,v 1.4 2003/07/19 21:14:34 dillon Exp $
28  */
29
30 /*
31  * ATAPI Floppy, LS-120 driver
32  */
33
34 #include "wdc.h"
35
36 #include <sys/param.h>
37 #include <sys/systm.h>
38 #include <sys/kernel.h>
39 #include <sys/conf.h>
40 #include <sys/proc.h>
41 #include <sys/malloc.h>
42 #include <sys/buf.h>
43 #include <sys/devicestat.h>
44 #include <sys/disklabel.h>
45 #include <sys/diskslice.h>
46 #include <sys/cdio.h>
47
48 #include <i386/isa/atapi.h>
49
50 static  d_open_t        wfdopen;
51 static  d_close_t       wfdclose;
52 static  d_ioctl_t       wfdioctl;
53 static  d_strategy_t    wfdstrategy;
54
55 #define CDEV_MAJOR 87
56 #define BDEV_MAJOR 1
57
58 static struct cdevsw wfd_cdevsw = {
59         /* open */      wfdopen,
60         /* close */     wfdclose,
61         /* read */      physread,
62         /* write */     physwrite,
63         /* ioctl */     wfdioctl,
64         /* poll */      nopoll,
65         /* mmap */      nommap,
66         /* strategy */  wfdstrategy,
67         /* name */      "wfd",
68         /* maj */       CDEV_MAJOR,
69         /* dump */      nodump,
70         /* psize */     nopsize,
71         /* flags */     D_DISK,
72         /* bmaj */      BDEV_MAJOR
73 };
74
75 int  wfdattach(struct atapi*, int, struct atapi_params*, int);
76
77 #define NUNIT   (NWDC*2)                /* Max. number of devices */
78 #define UNIT(d) ((minor(d) >> 3) & 3)   /* Unit part of minor device number */
79
80 #define F_BOPEN         0x0001          /* The block device is opened */
81 #define F_MEDIA_CHANGED 0x0002          /* The media have changed since open */
82 #define F_DEBUG         0x0004          /* Print debug info */
83
84 /*
85  * LS-120 Capabilities and Mechanical Status Page
86  */
87 struct cappage {
88     /* Mode data header */
89     u_short     data_length;
90     u_char      medium_type;
91 #define MDT_UNKNOWN     0x00
92 #define MDT_NO_DISC     0x70
93 #define MDT_DOOR_OPEN   0x71
94 #define MDT_FMT_ERROR   0x72
95
96 #define MDT_2DD_UN      0x10
97 #define MDT_2DD         0x11
98 #define MDT_2HD_UN      0x20
99 #define MDT_2HD_12_98   0x22
100 #define MDT_2HD_12      0x23
101 #define MDT_2HD_144     0x24
102 #define MDT_LS120       0x31
103
104     unsigned        reserved0       :7;
105     unsigned        wp              :1;     /* Write protect */
106     u_char          reserved1[4];
107
108     /* Capabilities page */
109     unsigned        page_code       :6;     /* Page code - Should be 0x5 */
110 #define CAP_PAGE        0x05
111     unsigned        reserved1_6     :1;     /* Reserved */
112     unsigned        ps              :1;     /* The device is capable of saving the page */
113     u_char          page_length;            /* Page Length - Should be 0x1e */
114     u_short         transfer_rate;          /* In kilobits per second */
115     u_char          heads, sectors;         /* Number of heads, Number of sectors per track */
116     u_short         sector_size;            /* Byes per sector */
117     u_short         cyls;                   /* Number of cylinders */
118     u_char          reserved10[10];
119     u_char          motor_delay;            /* Motor off delay */
120     u_char          reserved21[7];
121     u_short         rpm;                    /* Rotations per minute */
122     u_char          reserved30[2];
123 };
124
125 struct wfd {
126         struct atapi *ata;              /* Controller structure */
127         int unit;                       /* IDE bus drive unit */
128         int lun;                        /* Logical device unit */
129         int flags;                      /* Device state flags */
130         int refcnt;                     /* The number of raw opens */
131         int maxblks;                    /* transfer size limit */
132         struct buf_queue_head buf_queue;  /* Queue of i/o requests */
133         struct atapi_params *param;     /* Drive parameters table */
134         struct cappage cap;             /* Capabilities page info */
135         char description[80];           /* Device description */
136         struct diskslices *dk_slices;   /* virtual drives */
137
138         struct devstat device_stats;
139 };
140
141 static struct wfd *wfdtab[NUNIT]; /* Drive info by unit number */
142 static int wfdnlun = 0;           /* Number of configured drives */
143
144 static void wfd_start (struct wfd *t);
145 static void wfd_done (struct wfd *t, struct buf *bp, int resid,
146         struct atapires result);
147 static void wfd_error (struct wfd *t, struct atapires result);
148 static int wfd_request_wait (struct wfd *t, u_char cmd, u_char a1, u_char a2,
149         u_char a3, u_char a4, u_char a5, u_char a6, u_char a7, u_char a8,
150         u_char a9, char *addr, int count);
151 static void wfd_describe (struct wfd *t);
152 static int wfd_eject (struct wfd *t, int closeit);
153
154 /*
155  * Dump the array in hexadecimal format for debugging purposes.
156  */
157 static void wfd_dump (int lun, char *label, void *data, int len)
158 {
159         u_char *p = data;
160
161         printf ("wfd%d: %s %x", lun, label, *p++);
162         while (--len > 0)
163                 printf ("-%x", *p++);
164         printf ("\n");
165 }
166
167 int 
168 wfdattach (struct atapi *ata, int unit, struct atapi_params *ap, int debug)
169 {
170         struct wfd *t;
171         struct atapires result;
172         int lun, i;
173
174         if (wfdnlun >= NUNIT) {
175                 printf ("wfd: too many units\n");
176                 return (0);
177         }
178         if (!atapi_request_immediate) {
179                 printf("wfd: configuration error, ATAPI core code not present!\n");
180                 printf("wfd: check `options ATAPI_STATIC' in your kernel config file!\n");
181                 return (0);
182         }
183         t = malloc (sizeof (struct wfd), M_TEMP, M_NOWAIT);
184         if (! t) {
185                 printf ("wfd: out of memory\n");
186                 return (0);
187         }
188         wfdtab[wfdnlun] = t;
189         bzero (t, sizeof (struct wfd));
190         bufq_init(&t->buf_queue);
191         t->ata = ata;
192         t->unit = unit;
193         lun = t->lun = wfdnlun;
194         t->param = ap;
195         t->flags = F_MEDIA_CHANGED;
196         t->refcnt = 0;
197         if (debug) {
198                 t->flags |= F_DEBUG;
199                 /* Print params. */
200                 wfd_dump (t->lun, "info", ap, sizeof *ap);
201         }
202
203         /* Get drive capabilities. */
204         /* Do it twice to avoid the stale media changed state. */
205         for (i = 0; i < 2; i++) {
206                 result = atapi_request_immediate (ata, unit, ATAPI_MODE_SENSE,
207                         0, CAP_PAGE, 0, 0, 0, 0, 
208                         sizeof (t->cap) >> 8, sizeof (t->cap),
209                         0, 0, 0, 0, 0, 0, 0, (char*) &t->cap, sizeof (t->cap));
210         }
211
212         if (result.code == RES_ERR &&
213             (result.error & AER_SKEY) == AER_SK_UNIT_ATTENTION)
214                 result = atapi_request_immediate (ata, unit, ATAPI_MODE_SENSE,
215                         0, CAP_PAGE, 0, 0, 0, 0, sizeof (t->cap) >> 8,
216                         sizeof (t->cap), 0, 0, 0, 0, 0, 0, 0,
217                         (char*) &t->cap, sizeof (t->cap));
218
219         /* Some drives have shorter capabilities page. */
220         if (result.code == RES_UNDERRUN)
221                 result.code = 0;
222
223         if (result.code == 0) {
224                 wfd_describe (t);
225                 if (t->flags & F_DEBUG)
226                         wfd_dump (t->lun, "cap", &t->cap, sizeof t->cap);
227         } else
228                 return -1;
229
230         /*
231          * The IOMEGA ZIP 100, at firmware 21.* and 23.* at least
232          * is known to lock up if transfers > 64 blocks are
233          * requested.
234          */
235         if (!strcmp(ap->model, "IOMEGA  ZIP 100       ATAPI")) {
236                 printf("wfd%d: buggy Zip drive, 64-block transfer limit set\n",
237                        t->lun);
238                 t->maxblks = 64;
239         } else {
240                 t->maxblks = 0; /* no limit */
241         }
242         
243         
244
245         make_dev(&wfd_cdevsw, dkmakeminor(t->lun, WHOLE_DISK_SLICE, RAW_PART),
246             UID_ROOT, GID_OPERATOR, 0640, "rwfd%d", t->lun);
247
248         /*
249          * Export the drive to the devstat interface.
250          */
251         devstat_add_entry(&t->device_stats, "wfd", 
252                           t->lun, t->cap.sector_size,
253                           DEVSTAT_NO_ORDERED_TAGS,
254                           DEVSTAT_TYPE_FLOPPY | DEVSTAT_TYPE_IF_IDE,
255                           DEVSTAT_PRIORITY_WFD);
256         wfdnlun++;
257         return (1);
258 }
259
260 void wfd_describe (struct wfd *t)
261 {
262         int no_print = 0;
263
264         t->cap.cyls = ntohs (t->cap.cyls);
265         t->cap.sector_size = ntohs (t->cap.sector_size);
266
267         printf ("wfd%d: ", t->lun);
268         switch (t->cap.medium_type) {
269         case MDT_UNKNOWN:
270                 printf ("medium type unknown (no disk)");
271                 no_print = 1;
272                 break;
273         case MDT_2DD_UN:
274                 printf ("2DD(capacity unknown) floppy disk loaded");
275                 no_print = 1;
276                 break;
277         case MDT_2DD:
278                 printf ("720KB floppy disk loaded");
279                 break;
280         case MDT_2HD_UN:
281                 printf ("2HD(capacity unknown) floppy disk loaded");
282                 no_print = 1;
283                 break;
284         case MDT_2HD_12_98:
285                 printf ("1.25MB(PC-9801 format) floppy disk loaded");
286                 break;
287         case MDT_2HD_12:
288                 printf ("1.2MB floppy disk loaded");
289                 break;
290         case MDT_2HD_144:
291                 printf ("1.44MB floppy disk loaded");
292                 break;
293         case MDT_LS120:
294                 printf ("120MB floppy disk loaded");
295                 break;
296         case MDT_NO_DISC:
297                 printf ("no disc inside");
298                 no_print = 1;
299                 break;
300         case MDT_DOOR_OPEN:
301                 printf ("door open");
302                 no_print = 1;
303                 break;
304         case MDT_FMT_ERROR:
305                 printf ("medium format error");
306                 no_print = 1;
307                 break;
308         default:
309                 printf ("medium type=0x%x", t->cap.medium_type);
310                 break;
311         }
312         if (t->cap.wp)
313                 printf(", write protected");
314         printf ("\n");
315
316         if (!no_print) {
317                 printf ("wfd%d: ", t->lun);
318                 printf ("%u cyls", t->cap.cyls);
319                 printf (", %u heads, %u S/T", t->cap.heads, t->cap.sectors);
320                 printf (", %u B/S", t->cap.sector_size);
321                 printf ("\n");
322         }
323 }
324
325 int wfdopen (dev_t dev, int flags, int fmt, struct proc *p)
326 {
327         int lun = UNIT(dev);
328         struct wfd *t;
329         struct atapires result;
330         int errcode = 0;
331         struct disklabel label;
332
333         /* Check that the device number is legal
334          * and the ATAPI driver is loaded. */
335         if (lun >= wfdnlun || ! atapi_request_immediate)
336                 return (ENXIO);
337         t = wfdtab[lun];
338
339         t->flags &= ~F_MEDIA_CHANGED;
340         /* Lock the media. */
341         wfd_request_wait (t, ATAPI_PREVENT_ALLOW,
342                           0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0);
343
344         /* Sense the media type */
345         result = atapi_request_wait (t->ata, t->unit, ATAPI_MODE_SENSE,
346                                      0, CAP_PAGE, 0, 0, 0, 0, 
347                                      sizeof (t->cap) >> 8, sizeof (t->cap),
348                                      0, 0, 0, 0, 0, 0, 0, 
349                                      (char*) &t->cap, sizeof (t->cap));
350         if (result.code)
351                 printf ("wfd%d: Sense the media type is failed.\n", t->lun);
352         else {
353                 t->cap.cyls = ntohs (t->cap.cyls);
354                 t->cap.sector_size = ntohs (t->cap.sector_size);
355         }
356
357         /* Build label for whole disk. */
358         bzero(&label, sizeof label);
359         label.d_secsize = t->cap.sector_size;
360         label.d_nsectors = t->cap.sectors;
361         label.d_ntracks = t->cap.heads;
362         label.d_ncylinders = t->cap.cyls;
363         label.d_secpercyl = t->cap.heads * t->cap.sectors;
364         label.d_rpm = 720;
365         label.d_secperunit = label.d_secpercyl * t->cap.cyls;
366
367         /* Initialize slice tables. */
368         errcode = dsopen(dev, fmt, 0, &t->dk_slices, &label);
369         if (errcode != 0)
370                 return errcode;
371
372         t->flags |= F_BOPEN;
373         return (0);
374 }
375
376 /*
377  * Close the device.  Only called if we are the LAST
378  * occurence of an open device.
379  */
380 int wfdclose (dev_t dev, int flags, int fmt, struct proc *p)
381 {
382         int lun = UNIT(dev);
383         struct wfd *t = wfdtab[lun];
384
385         dsclose(dev, fmt, t->dk_slices);
386         if(!dsisopen(t->dk_slices)) {
387                 /* If we were the last open of the entire device, release it. */
388                 if (! t->refcnt)
389                         wfd_request_wait (t, ATAPI_PREVENT_ALLOW,
390                                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
391                 t->flags &= ~F_BOPEN;
392         }
393         return (0);
394 }
395
396 /*
397  * Actually translate the requested transfer into one the physical driver can
398  * understand. The transfer is described by a buf and will include only one
399  * physical transfer.
400  */
401 void wfdstrategy (struct buf *bp)
402 {
403         int lun = UNIT(bp->b_dev);
404         struct wfd *t = wfdtab[lun];
405         int x;
406
407         /* If it's a null transfer, return immediatly. */
408         if (bp->b_bcount == 0) {
409                 bp->b_resid = 0;
410                 biodone (bp);
411                 return;
412         }
413
414         /*
415          * Do bounds checking, adjust transfer, and set b_pblkno.
416          */
417         if (dscheck(bp, t->dk_slices) <= 0) {
418                 biodone(bp);
419                 return;
420         }
421
422         x = splbio();
423
424         /* Place it in the queue of disk activities for this disk. */
425         bufqdisksort (&t->buf_queue, bp);
426
427         /* Tell the device to get going on the transfer if it's
428          * not doing anything, otherwise just wait for completion. */
429         wfd_start (t);
430         splx(x);
431 }
432
433 /*
434  * Look to see if there is a buf waiting for the device
435  * and that the device is not already busy. If both are true,
436  * It dequeues the buf and creates an ATAPI command to perform the
437  * transfer in the buf.
438  * The bufs are queued by the strategy routine (wfdstrategy).
439  * Must be called at the correct (splbio) level.
440  */
441 static void wfd_start (struct wfd *t)
442 {
443         struct buf *bp = bufq_first(&t->buf_queue);
444         u_long blkno, nblk;
445         u_char op_code;
446         long count;
447         int pxcount, pxnblk;
448         u_char *pxdest;
449         
450
451         /* See if there is a buf to do and we are not already doing one. */
452         if (! bp)
453                 return;
454
455         /* Unqueue the request. */
456         bufq_remove(&t->buf_queue, bp);
457
458         /* Tell devstat we are starting on the transaction */
459         devstat_start_transaction(&t->device_stats);
460
461         /* We have a buf, now we should make a command
462          * First, translate the block to absolute and put it in terms of the
463          * logical blocksize of the device. */
464         blkno = bp->b_pblkno / (t->cap.sector_size / 512);
465         nblk = (bp->b_bcount + (t->cap.sector_size - 1)) / t->cap.sector_size;
466
467         if ((t->maxblks == 0) || (nblk <= t->maxblks)) {
468
469                 if(bp->b_flags & B_READ) {
470                         op_code = ATAPI_READ_BIG;
471                         count = bp->b_bcount;
472                 } else {
473                         op_code = ATAPI_WRITE_BIG;
474                         count = -bp->b_bcount;
475                 }
476
477                 /* only one transfer */
478                 (int)bp->b_driver1 = 0;
479                 (int)bp->b_driver2 = 0;
480                 atapi_request_callback (t->ata, t->unit, op_code, 0,
481                                         blkno>>24, blkno>>16, blkno>>8, blkno,
482                                         0, nblk>>8, nblk, 0, 0,
483                                         0, 0, 0, 0, 0, 
484                                         (u_char*) bp->b_data, count, 
485                                         (void*)wfd_done, t, bp);
486         } else {
487
488                 /*
489                  * We can't handle this request in a single
490                  * read/write operation.  Instead, queue a set of
491                  * transfers, and record the number of transfers
492                  * and the running residual in the b_driver
493                  * fields of the bp.
494                  */ 
495
496                 if(bp->b_flags & B_READ) {
497                         op_code = ATAPI_READ_BIG;
498                 } else {
499                         op_code = ATAPI_WRITE_BIG;
500                 }
501
502                 /* calculate number of transfers */
503                 (int)bp->b_driver1 = (nblk - 1) / t->maxblks;
504                 (int)bp->b_driver2 = 0;
505
506                 pxdest = (u_char *)bp->b_data;
507                 pxcount = bp->b_bcount;
508
509                 /* construct partial transfer requests */
510                 while (nblk > 0) {
511                         pxnblk = min(nblk, t->maxblks);
512                         count = min(pxcount, t->maxblks * t->cap.sector_size);
513
514                         atapi_request_callback(t->ata, t->unit, op_code, 0,
515                                                blkno>>24, blkno>>16, blkno>>8,
516                                                blkno, 0, pxnblk>>8, pxnblk, 
517                                                0, 0, 0, 0, 0, 0, 0,
518                                                pxdest, 
519                                                (bp->b_flags & B_READ) ?
520                                                count : -count, 
521                                                (void*)wfd_done, t, bp);
522                         nblk -= pxnblk;
523                         pxcount -= count;
524                         pxdest += count;
525                         blkno += pxnblk;
526                 }
527         }
528 }
529
530 static void wfd_done (struct wfd *t, struct buf *bp, int resid,
531         struct atapires result)
532 {
533                 
534         if (result.code) {
535                 wfd_error (t, result);
536                 bp->b_error = EIO;
537                 bp->b_flags |= B_ERROR;
538         } else
539                 (int)bp->b_driver2 += resid;
540         /*
541          * We can't call biodone until all outstanding
542          * transfer fragments are handled.  If one hits
543          * an error, we will be returning an error, but
544          * only when all are complete.
545          */
546         if (((int)bp->b_driver1)-- <= 0) {
547                 bp->b_resid = (int)bp->b_driver2;
548                 devstat_end_transaction_buf(&t->device_stats, bp);
549                 biodone (bp);
550         }
551         
552         wfd_start (t);
553 }
554
555 static void wfd_error (struct wfd *t, struct atapires result)
556 {
557         if (result.code != RES_ERR)
558                 return;
559         switch (result.error & AER_SKEY) {
560         case AER_SK_NOT_READY:
561                 if (result.error & ~AER_SKEY) {
562                         /* Not Ready */
563                         printf ("wfd%d: not ready\n", t->lun);
564                         return;
565                 }
566                 /* Tray open. */
567                 if (! (t->flags & F_MEDIA_CHANGED))
568                         printf ("wfd%d: tray open\n", t->lun);
569                 t->flags |= F_MEDIA_CHANGED;
570                 return;
571
572         case AER_SK_UNIT_ATTENTION:
573                 /* Media changed. */
574                 if (! (t->flags & F_MEDIA_CHANGED))
575                         printf ("wfd%d: media changed\n", t->lun);
576                 t->flags |= F_MEDIA_CHANGED;
577                 return;
578
579         case AER_SK_ILLEGAL_REQUEST:
580                 /* Unknown command or invalid command arguments. */
581                 if (t->flags & F_DEBUG)
582                         printf ("wfd%d: invalid command\n", t->lun);
583                 return;
584         }
585         printf ("wfd%d: i/o error, status=%b, error=%b\n", t->lun,
586                 result.status, ARS_BITS, result.error, AER_BITS);
587 }
588
589 static int wfd_request_wait (struct wfd *t, u_char cmd, u_char a1, u_char a2,
590         u_char a3, u_char a4, u_char a5, u_char a6, u_char a7, u_char a8,
591         u_char a9, char *addr, int count)
592 {
593         struct atapires result;
594
595         result = atapi_request_wait (t->ata, t->unit, cmd,
596                 a1, a2, a3, a4, a5, a6, a7, a8, a9, 0, 0, 0, 0, 0, 0,
597                 addr, count);
598         if (result.code) {
599                 wfd_error (t, result);
600                 return (EIO);
601         }
602         return (0);
603 }
604
605 /*
606  * Perform special action on behalf of the user.
607  * Knows about the internals of this device
608  */
609 int wfdioctl (dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p)
610 {
611         int lun = UNIT(dev);
612         struct wfd *t = wfdtab[lun];
613         int error = 0;
614
615         error = dsioctl(dev, cmd, addr, flag, &t->dk_slices);
616         if (error != ENOIOCTL)
617                 return (error);
618
619         if (t->flags & F_MEDIA_CHANGED)
620                 switch (cmd) {
621                 case CDIOCSETDEBUG:
622                 case CDIOCCLRDEBUG:
623                 case CDIOCRESET:
624                         /* These ops are media change transparent. */
625                         break;
626                 default:
627                         /* Lock the media. */
628                         wfd_request_wait (t, ATAPI_PREVENT_ALLOW,
629                                 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0);
630                         break;
631                 }
632         switch (cmd) {
633         case CDIOCSETDEBUG:
634                 error = suser(td);
635                 if (error)
636                         return (error);
637                 t->flags |= F_DEBUG;
638                 atapi_debug (t->ata, 1);
639                 return 0;
640         case CDIOCCLRDEBUG:
641                 error = suser(td);
642                 if (error)
643                         return (error);
644                 t->flags &= ~F_DEBUG;
645                 atapi_debug (t->ata, 0);
646                 return 0;
647         case CDIOCRESET:
648                 error = suser(td);
649                 if (error)
650                         return (error);
651                 return wfd_request_wait (t, ATAPI_TEST_UNIT_READY,
652                         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
653         case CDIOCEJECT:
654                 /* Don't allow eject if the device is opened
655                  * by somebody (not us) in block mode. */
656                 if ((t->flags & F_BOPEN) && t->refcnt)
657                         return (EBUSY);
658                 return wfd_eject (t, 0);
659         case CDIOCCLOSE:
660                 if ((t->flags & F_BOPEN) && t->refcnt)
661                         return (0);
662                 return wfd_eject (t, 1);
663         default:
664                 return (ENOTTY);
665         }
666         return (error);
667 }
668
669 static int wfd_eject (struct wfd *t, int closeit)
670 {
671         struct atapires result;
672
673         /* Try to stop the disc. */
674         result = atapi_request_wait (t->ata, t->unit, ATAPI_START_STOP,
675                 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
676
677         if (result.code == RES_ERR &&
678             ((result.error & AER_SKEY) == AER_SK_NOT_READY ||
679             (result.error & AER_SKEY) == AER_SK_UNIT_ATTENTION)) {
680                 int err;
681
682                 if (!closeit)
683                         return (0);
684                 /*
685                  * The disc was unloaded.
686                  * Load it (close tray).
687                  * Read the table of contents.
688                  */
689                 err = wfd_request_wait (t, ATAPI_START_STOP,
690                         0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0);
691                 if (err)
692                         return (err);
693
694                 /* Lock the media. */
695                 wfd_request_wait (t, ATAPI_PREVENT_ALLOW,
696                         0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0);
697
698                 return (0);
699         }
700
701         if (result.code) {
702                 wfd_error (t, result);
703                 return (EIO);
704         }
705
706         if (closeit)
707                 return (0);
708
709         /* Give it some time to stop spinning. */
710         tsleep ((caddr_t)&lbolt, 0, "wfdej1", 0);
711         tsleep ((caddr_t)&lbolt, 0, "wfdej2", 0);
712
713         /* Unlock. */
714         wfd_request_wait (t, ATAPI_PREVENT_ALLOW,
715                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
716
717         /* Eject. */
718         t->flags |= F_MEDIA_CHANGED;
719         return wfd_request_wait (t, ATAPI_START_STOP,
720                 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0);
721 }
722
723 static void     wfd_drvinit(void *unused)
724 {
725         cdevsw_add(&wfd_cdevsw);
726 }
727
728 SYSINIT(wfddev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,wfd_drvinit,NULL)