FreeBSD/Linux Kernel Cross Reference
sys/i386/isa/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.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
|