proc->thread stage 4: rework the VFS and DEVICE subsystems to take thread
[dragonfly.git] / sys / dev / disk / wfd / wfd.c
CommitLineData
984263bc
MD
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 $
dadab5e9 27 * $DragonFly: src/sys/dev/disk/wfd/Attic/wfd.c,v 1.3 2003/06/25 03:55:54 dillon Exp $
984263bc
MD
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
50static d_open_t wfdopen;
51static d_close_t wfdclose;
52static d_ioctl_t wfdioctl;
53static d_strategy_t wfdstrategy;
54
55#define CDEV_MAJOR 87
56#define BDEV_MAJOR 1
57
58static 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
75int 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 */
87struct 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
125struct 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
141static struct wfd *wfdtab[NUNIT]; /* Drive info by unit number */
142static int wfdnlun = 0; /* Number of configured drives */
143
144static void wfd_start (struct wfd *t);
145static void wfd_done (struct wfd *t, struct buf *bp, int resid,
146 struct atapires result);
147static void wfd_error (struct wfd *t, struct atapires result);
148static 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);
151static void wfd_describe (struct wfd *t);
152static int wfd_eject (struct wfd *t, int closeit);
153
154/*
155 * Dump the array in hexadecimal format for debugging purposes.
156 */
157static 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
167int
168wfdattach (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
260void 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
325int 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 */
380int 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 */
401void 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 */
441static 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
530static 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
555static 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
589static 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 */
609int 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:
dadab5e9 634 error = suser(td);
984263bc
MD
635 if (error)
636 return (error);
637 t->flags |= F_DEBUG;
638 atapi_debug (t->ata, 1);
639 return 0;
640 case CDIOCCLRDEBUG:
dadab5e9 641 error = suser(td);
984263bc
MD
642 if (error)
643 return (error);
644 t->flags &= ~F_DEBUG;
645 atapi_debug (t->ata, 0);
646 return 0;
647 case CDIOCRESET:
dadab5e9 648 error = suser(td);
984263bc
MD
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
669static 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, PRIBIO, "wfdej1", 0);
711 tsleep ((caddr_t)&lbolt, PRIBIO, "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
723static void wfd_drvinit(void *unused)
724{
725 cdevsw_add(&wfd_cdevsw);
726}
727
728SYSINIT(wfddev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,wfd_drvinit,NULL)